Django context variable names for the templates - python

EDIT:
I know I can change the names of the variables. My question is in the case that I don't want to do that. I want to know what are all the variables that django generates automatically.
I'm doing Django's getting started tutorial and I'm on the generic views section where at one point it explains:
In previous parts of the tutorial, the templates have been provided
with a context that contains the question and latest_question_list
context variables. For DetailView the question variable is provided
automatically – since we’re using a Django model (Question), Django is
able to determine an appropriate name for the context variable.
However, for ListView, the automatically generated context variable is
question_list.
My problem is that I don't know how Django determines this "appropriate names". I want to know this for when I write my own template. I would want to know what context variable names to use in such template.
From what I can understand, if my model is Question, the question context variable would store that question, and the question_list context variable would store every question.
So my doubt is: What other context variables names can I use? and what would they store? I can't seem to find this on the documentation, please redirect me to it if you know where it is.

You can change the question_list to something else by using the context_object_name this isn't explained all that well in that part of the documentation, but ...
Return the context variable name that will be used to contain the list
of data that this view is manipulating. If object_list is a queryset
of Django objects and context_object_name is not set, the context name
will be the model_name of the model that the queryset is composed
from, with postfix '_list' appended. For example, the model Article
would have a context object named article_list.
is given under get_context_object_name method
This is what that method's code looks like, It ought to clear up all doubts:
"""
Get the name of the item to be used in the context.
"""
if self.context_object_name:
return self.context_object_name
elif hasattr(object_list, 'model'):
return '%s_list' % object_list.model._meta.model_name
else:
return None

I think this default context variable name only applies when dealing with Django's Class Based Views.
E.g. If you are using a DetailView for a Animal model, Django will auto create a context variable called 'animal' for you to use in template. I think it also allows the use of 'object'.
Another example is, as you mentioned, the ListView for a Animal model which would generate context name called animal_list.
However, in both of these cases, there are ways to change the default context variable name. If you specify 'context_object_name' in your DetailView, this will be the name you refer to in your template. This will also work for ListViews.
This website has all info on CBVs of all Django versions:
https://ccbv.co.uk/projects/Django/1.9/django.views.generic.detail/DetailView/

Related

Group list items by field value in the Django admin

I'm trying to group the items in the Django admin app by a specific field (e.g. date).
So I've added to the queryset in admin.ModelAdmin.getQueryset() the following:
queryset = queryset.values('date').annotate(Sum('amount'))
But this doesn't work because in this case, a dict is returned instead of a queryset.
I started exploring what's inside the django/contrib/admin folder, and I think something need to be done before sending the object to the template change_list.html.
I'm not sure but I think the class in views/main.py (admin folder) might need some change.
Can anybody confirm that what I'm trying to do is achievable at all?
Please find below a representation of what I'm trying to achieve:
Follow the below example in URL. it's has great way to understand with override django admin with custom queryset and groupby data
https://medium.com/#hakibenita/how-to-turn-django-admin-into-a-lightweight-dashboard-a0e0bbf609ad
I found this useful: https://github.com/xacce/django_admin_grouper
You can simply define the group in ClassAdmin
class RecordAdmin(admin.ModelAdmin):
def regroup_by(self):
return 'category'
The repo overrides Django's change_list_results.html. If your RecordAdmin has method reggroup_by than it inserts a row with the name of the category. If reggroup_by is missing it works as usual.

Why is my django template setting user to the same as object?

I'm a definite newbie to django, and have used tutorials and stack overflow a lot to design my app.
My app tracks casework for users. One thing I need it to be able to do is to be logged in as one user, and look at the caseload for another user.
When this page comes up, the bit that would normally say "Logout Joe Bloggs", where Joe Bloggs is the logged in user, says "Logout Fitzwilliam Darcy" where Fitzwilliam Darcy is the user I should be viewing the casework of.
I don't really want to continue developing the app until I've fixed it, in case this is a symptom of an underlying problem that will cause more issues in future.
I'll add what I think all the relevant bits are here, but if there's anything else needed, let me know and I'll be happy to edit.
#urls.py
url(r'cases/(?P<slug>\w+)',views.UserCasesView.as_view(),name='cases'),
#views.py
#method_decorator(login_required,name='dispatch')
class UserCasesView(generic.DetailView):
model = models.User
template_name = 'caseworkclub/caseworker_detail.html'
slug_field = 'username'
#models.py
class User(AbstractUser):
association = models.ForeignKey('Association',null=True)
def full_name(self):
return("{} {}".format(self.first_name,self.last_name)
def open_cases(self):
return(Case.objects.filter(closed__isnull=True,caseworker=self))
The slug bit is so that the username can be in the URL according to this answer to another question
It might also be worth explaining, if the models.py bit doesn't give it away, that I've extended the base user class and am using that, rather than the user profile technique. The problem seems to have come about since changing the slug bit above, though.
Any help hugely appreciated, and as I said - any more info, happy to provide!
James
This is because you did not override the get_context_data() method of your UserCasesView class with a sensible default. It currently uses the model name (which also happens to be user) which conflicts with the built-in user variable which is set by django.contrib.auth.context_processors.auth context processor.
From the documentation:
Context variables override values from template context processors
Any variables from get_context_data() take precedence over context variables from context processors. For example, if your view sets the model attribute to User, the default context object name of user would override the user variable from the django.contrib.auth.context_processors.auth() context processor. Use get_context_object_name() to avoid a clash.
Try changing the object name from user to something else (such as case_user):
class UserCasesView(generic.DetailView):
...
context_object_name = 'case_user'

How do I create global elements in a Django template that reference a database?

I am working with the Django templating system as a beginner, and I had a question. Many times in web apps I have made in the past I have some sort of global element (as in its seen on almost all pages) on the page that references the database or active session.
An example of the active session would be someones name at the top of the page with a link to logout.
An example of the element that references the database would be a box that displays recent posting or login statistics.
With the templating system, it seems that the information available is primarily that which can be passed through as the "context". How can I go about achieving what I would like? Am I even thinking about how to construct things properly with Django or have I missed the point?
I apologize if this has been asked, I simply couldn't find a way to word it where I got results relevant to my question.
Thanks!
You should probably read the Django Template Language documentation. In a nutshell, a context is a Python dictionary of name/value pairs, where the names are referenced in a template and the value is substituted for the name. For example,
context = {'user': request.user} # assign the current user to the context 'user'
return render_to_response('my_template.html', context)
will pass the current user to my_template.html. Then, inside that template, {{ user.name }} will display that user's name. The important thing is that you can reference the variable by the context name and treat it like a Python object (referencing the user's name as a attribute).

Django Generic Views: When to use ListView vs. DetailView

I am using Django's class based generic views in a blog application. One of my views displays a list of posts that have a certain tag. I can write this view as a ListView of posts, filtered by tag. Or I can write this view as a DetailView of the tag, and add the relevant posts to the context.
Is one way more proper -- or Pythonic -- than the other?
The ListView approach seems more semantic, because what I want is a list of posts, but it's also slightly more complex. It requires that I overwrite two methods. The DetailView approach only requires me to overwrite one method.
class PostTagView(ListView):
"""Display all blog posts with a given tag."""
queryset = Post.objects.published()
def get_context_data(self, **kwargs):
context = super(PostTagView, self).get_context_data(**kwargs)
context['tag'] = get_object_or_404(Tag, slug=self.kwargs['slug'])
return context
def get_queryset(self, **kwargs):
queryset = super(PostTagView, self).get_queryset()
return queryset.filter(tags__slug=self.kwargs['slug'])
class TagDetailView(DetailView):
"""Display all blog posts with a given tag."""
model = Tag
def get_context_data(self, **kwargs):
context = super(TagDetailView, self).get_context_data(**kwargs)
context['object_list'] = Post.objects.published().filter(tags__slug=self.kwargs['slug'])
return context
As a rule of thumb, look at the parameters in the URL. If you're using a slug of a Tag then you're most likely dealing with a DetailView and not a ListView.
In this case, the second approach uses less code and it is more elegant. However, it also depends on what you're going to do with the view later on. If you're going to add forms to edit the posts, it might make sense to use a ListView instead. But there's no technical reason to prefer one over the other, it's just that you might end up writing more code in one approach than in the other.
Both ListView and DetailView are not the same technically,
For example you cannot give the path for a DetailView like the below in urls.py,
path('schools_detail/',views.SchoolDetailView.as_view(),name = "detail"),
This will give the below error,
Generic detail view SchoolDetailView must be called with either an
object pk or a slug in the URLconf.
This means that if we have a table called Student and another table called School, we can use the ListView to list all the schools like below,
path('list/',views.SchoolListView.as_view(),name = "list"),
And if we want to list the Schools details for individual school when we click the school icon, then we can use the primary key of the School which Django creates internally and capture it in the url pattern, in my case the url pattern would be "list/{{school.id}}" so to capture this we have to give the path like below for DetailsView,
path('list/<int:pk>/',views.SchoolDetailView.as_view(),name = "detail"),
So Bottom line is you can use the ListView as a normal view for most of the cases, if you want to access another View but only a particular detail in that View which refers with a primary key then you can use DetailsView(the url pattern for the DetailsView will be generated by giving the primary key info in the url, without primary key in the url it wont work since it wont take all the info instead it will only take the info related to the primary key in the url)
Interesting question. Unfortunately, the answer is not quite so interesting: whichever makes the most sense for you and your app. Arguments could be made equally for either approach, so it's really just a judgement call.
The usecase for class based generic views are perfectly described in article:
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views
In above mentioned article, you'd be able to know when/why and how to use ListView/DetailView along with simple examples.

Django - Accessing object fields and names from class-based view

I'm trying to write a class-based view for Django which will utilise the same template each time, regardless of model. The intention is that I can then add a urls.py entry for each model, and not have to bother about a view or a template.
This will be used to display a form, and as the form field names are dependant on model type, the model needs to be examined and field names extracted at the view level, so they can be passed to the generic template. The template then generates the form based on field names and values of the object.
I've been really struggling with this. At the moment I'm working on overriding get_context_data as follows
def get_context_data(self, **kwargs):
context = kwargs
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
#add some custom stuff on too
tempdict = [(field, field.value_to_string(self)) for field in self.object._meta.fields]
#context.update({'datafields' : tempdict})
context.update({ 'blarg': 'tester!!'})
return context
The self.object._meta.fields bit is where I'm haivng the problems. I just can't get my head around how to access the current model. I'm doing this in a view, woud I have aany more luck in a mixin?
Thanks for your time.
O
I think you're going about this the wrong way. Django already knows how to create a form from a model, and forms know how to output themselves. So you can create a standard generic view using ModelFormMixin, there's no need to do anything clever to get form fields for a model's fields.
The only difficult bit is that you want one view to work for multiple models. So, rather than declaring the model explicitly on the view class, you'll need to work out some way of passing it dynamically - perhaps by overriding get_object.
If you're using django 1.3, class based views are included... Just use them and set the 'template_name' attribute to be your "common" name.
https://docs.djangoproject.com/en/1.3/topics/class-based-views/

Categories

Resources