Django Admin multiple template inheritance - python

I thought it was a quite simple task but turns out it's not.
So, I have two different mixins to use on a Django admin class. they both have some codes in it with templates.
admin.py
class AdminMixin01(admin.ModelAdmin):
change_form_template = "change_form1.html"
class AdminMixin02(admin.ModelAdmin):
change_form_template = "change_form2.html"
class ModalAdmin(AdminMixin01, AdminMixin02, admin.ModelAdmin):
pass
change_form1.html
{% extends "change_form.html" %}
{% block content %}
{{ block.super }}
Form 1
{% endblock content %}
change_form2.html
{% extends "change_form.html" %}
{% block content %}
{{ block.super }}
Form 2
{% endblock content %}
it's looks quite simple both python and html sides.
The problem is Django renders only first mixin's template and ignores the second mixin's template. In this case only change_form1.html rendered into original change_form.html template and no traces from change_form2.html.
The python codes in the both mixin are working except html codes.
Any ideas ?

Related

Creating a custom template tag to replace the for loop - Django

I am trying to simplify my code by creating a custom template tag for a 'for loop' that use frequently on my Django web application. I thought it would be a simple straight process, but something isn't working right... I can use some assistance in catching my error.
Here is my code.
views.py
class ArticleView(DetailView):
model = Articles
def get_context_data(self, **kwargs):
context = super(ArticleView, self).get_context_data(**kwargs)
context['s_terms'] = scientific_terms.objects.all()
return context
template tag
#register.filter(name='term')
def term(value):
{% for term in s_terms %}
{{ term.short_description }}
{% endfor %}
template.html
{% Neurons|term %}
Thank you for your assistance, in advance.
You are mixing Python code with the Django Template Language. The template tags are plain Python code, as they are defined inside a Python module. A working example would be:
#register.filter(name='term')
def term(terms):
output = ''
for term in terms:
output = '{0} {1}'.format(output, term.short_description)
return output
Then you could use it like this:
{{ s_terms|term }}
Maybe what you want is simply to create a reusable Django template.
For example, create a new template named terms.html:
templates/terms.html
{% for term in terms %}
<p>{{ term.short_description }}</p>
{% endfor %}
Then, in another template, you could include this partial template:
templates/index.html (name is just an example)
{% extends 'base.html' %}
{% block content %}
<h1>My application</h1>
{% include 'terms.html' with terms=s_terms %}
{% endblock %}

Django: ListView. Where can I declare variables that I want to have on template?

One of my tables in my app is called Gallery and I have the following class to list all of the objects on that table:
from django.views.generic import ListView
from galleries.models import Gallery
class GalleryList(ListView):
template_name = "path/to/template"
context_object_name = "object_list"
def queryset(self):
return Gallery.objects.order_by('-title')[:20]
And it does the job. On my template I do the following:
{% block gallery_list %}
<h1>Gallery List</h1>
<ul>
{% for gallery in object_list %}
<li><img src="{{ gallery.thumbnail.url }}" />{{ gallery.title }}</li>
{% endfor %}
</ul>
{% endblock %}
Everything works as expected. The thing here is that on my base.html template I have {% block title %} for the meta title tag, {% block description %} for my meta description tag in the header. And I want to be able to declare it somewhere and pass it to the view. To be clear, the variables title and description are strings (ex: title="List of all galleries on website").
On the view I want to do something like:
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block description %}{{ description|default:title }}{% endblock %}
But, on the class GalleryList I don't know where to declare the variables title and description. I don't know if that's possible or proper for Django. I want to do what's right.
Also, as I have a costume template for listing all the galleries I could just do:
{% extends "base.html" %}
{% block title %}List of all galleries on website{% endblock %}
{% block description %}List of all galleries on website...{% endblock %}
But then again, I don't know if that's proper for a well coded Django app. I'm a beginner with Django and I would like to know what's the way to go about this. Hope my question is clear enough.
You can override the ListViews get_context_data method to add whatever additional context variables to you want to the context:
class GalleryList(ListView):
def get_context_data(self, **kwargs):
ctx = super(GalleryList, self).get_context_data(**kwargs)
ctx['title'] = 'My Title'
ctx['description'] = 'My Description'
return ctx
The other approach - of having a template that fills in this information - is also sound. Which is better really depends on how dynamic the data is. If the title/description is based on model data or some other factors, then it makes sense to set it in the view. If it is fixed for a particular template then it is probably cleaner to put in in a template that extends base.html.

Include tag in Django template language -- what can I pass in to it?

OK, so again there is likely a "simple" solution to this, but I am a beginner and nothing seems simple to me.
I have a view and a template that shows the attributes of an instance of a Car class that I have modeled. This Car class has a ManyToMany relationship with my custom User class. The template that show the attributes of a given instance of Car has many variables. The view for each Car works fine. Here is what I can't get to work:
I have a user profile page for each instance of User. From that page, I want to show the attributes of each Car that a particular User has "favorited." I am unable to figure out how to do this.
I have tried the {% include %} tag to include a snippet of the Car template and then use a for statement to iterate through the favorite set of the User. In theory, this would populate the User page with each Car that they have "favorited" and show its attributes. However, I do not know how to pass the {% include %} tag the proper context so the attributes are populated correctly for each instance of Car. Is this possible?
Is there a simpler way to do it that I am just overlooking?
Any help is appreciated. Thanks!
Use the {% include ... with ... %} syntax:
{% for car in user.favorite_cars.all %}
{% include "car.html" with name=car.name year=car.year %}
{% endfor %}
Another alternative is the {% with %} tag:
{% for car in user.favorite_cars.all %}
{% with name=car.name year=car.year %}
{% with color=car.color %}
{% include "car.html" %}
{% endwith %}
{% endwith %}
{% endfor %}
UPDATE: If data for the template can't be obtained from the Car model then you have to use the custom inclusion tag:
from django import template
register = template.Library()
#register.inclusion_tag('car.html')
def show_car(car):
history = get_history_for_car(car)
return {'name': car.name, 'history': history}
And the in the template:
{% load my_car_tags %}
{% for car in user.favorite_cars.all %}
{% show_car car %}
{% endfor %}

Is it possible to load a custom template tag in base and use it in extented templates

I loaded a custom template tag note_extras.py in base.html.
base.html
<div id="wrap">
{% load note_extras %}
{% block content %}
{% endblock %}
</div><!--wrap-->
but it is not accessible at templates which is an extend of base.html ie::
home.html
{% extends "base.html" %}
{% block content %}
<div class="container">
{% create_tagmenu request.user.pk %}
</div>
{% endblock %}
it is working fine if i load note_extras in home.html ie:
{% extends "base.html" %}
{% load note_extras %}
....
In Django template language, you must load all needed template libraries in each of the templates.
I personally think it is a good idea because it makes templates more explicit (which is better than implicit). Ill give an example. Prior to Django 1.5, the default behavior for a url tag was to provide the view name in plaintext as well as all the needed parameters:
{% url path.to.view ... %}
There however was no way to provide the path to the view via a context variable:
{% with var='path.to.view' %}
{% url var ... %}
{% endwith %}
To solve that, starting with 1.3, you could import the future version of the url tag (which became the default in 1.5) by doing:
{% load url from future %}
{% url var ... %}
or
{% url 'path.to.view' ... %}
Now imagine that you would need to create a template which would extend from a base template which you did not create (e.g. one of django admin base templates). Then imagine that within the base template it would have {% load url from future %}. As a result, {% url path.to.view ... %} within your template would become invalid without any explicit explanation.
Of course this example does not matter anymore (starting with 1.5) however hopefully it illustrates a point that being explicit in templates is better than implicit which is why the currently implementation is the way it is.
If you want that a template tag is loaded in every template you want to do it in the init file of your app:
from django.template.loader import add_to_builtins
add_to_builtins('my_app.templatetags.note_extras')
In case anyone was wondering, add_to_builtins has been deprecated but one could still load a tag for all of the templates in the project via settings.TEMPLATES - supported for Django 1.9 onwards as described here:
https://stackoverflow.com/a/59719364/2447803

Getting different django administration title

I am trying to get a different header in django administration. I would like to put the company's name there instead. I am trying to do it through the docs. https://docs.djangoproject.com/en/1.5/intro/tutorial02/
Near the bottem, it says to add a TEMPLATE_DIRS setting, which I did.
So, if I have:
'/LPG/firstproject/firstproject/templates',
in my TEMPLATE_DIRS
and this is where the django source file of base_html is at
/usr/local/lib/python2.7/dist-packages/django/contrib/admin/
What exactly does it mean when it says "Now copy the template admin/base_site.html from within the default Django admin template directory in the source code of Django itself"
Is this done with a command or how exactly do I do this?
Try this:
Inside your main template folder, create an admin folder. Inside it, create a file named base_site.html with the following content:
{% extends "admin/base.html" %}
{% load i18n %}
{% block title %}
{{ title }} | {% trans 'Your Site Title' %}
{% endblock %}
{% block branding %}
<h1 id="site-name">{% trans 'Your Site Title' %}</h1>
{% endblock %}
{% block nav-global %}{% endblock %}
Basically, if you want to override a django admin template, you have to match the path for the template and then create your own custom template.

Categories