Query multiple models with class-based views - django

I would like to solve the following situation.
I have a side panel containing information of the active user. For this an instance of UserInfo model needs to be passed to the views.
Additionally, I would like to pass a number of other model instances to the pages (eg. Purchases, Favourites, etc.).
I know this is pretty easy to do by overriding the get_context_data.
def get_context_data(self, **kwargs):
kwargs['purchases'] = Purchases.objects.get(id=1)
kwargs['favourites'] = Favourites.objects.get(id=1)
.... etc
return super(UploadFileView, self).get_context_data(**kwargs)
So my question is - what would be the best/most appropriate CBV to use for this?

This isn't quite a DetailView as you have multiple objects, but it isn't a ListView either, nor does it look like a FormView or its children.
Since you gain nothing from those, a simple TemplateView is probably the way to go.

If you are querying the same UserInfo, Purchases, Favorites, etc in multiple views, create a Mixin that you can re-use.
class CommonUserInfoMixin (object):
def get_context_data(self, **kwargs):
context = super(OrgContextMixin, self).get_context_data(**kwargs)
... # Add more to context object
Then you can use this in your normal List, Detail, Update, etc CBV's
class ItemList(CommonUserInfoMixin, ListView):
....

Related

Accessing model/class information within context processor

In my Django app I have a series of generic views (create, update, delete, detail, list) that most of my actual views inherit from. All of these views add a number of pieces of useful information to the context (the singular and plural names of the model, the urls for creating, listing, etc). But the views more-or-less all duplicate the same code. For that reason I'd like to move these things to a context processor and remove the code duplication.
My issue is, I can't seem to determine the things I would need from the request that's passed to the context processor (ie: if I could access the model instance, model class, form class, etc), then Id be fine. The code below shows what the get_context_data looks like within the views - how would I replicate this in a context processor?
Thanks.
def get_context_data(self, **kwargs):
"""Passes context variables to the HTML templates."""
context = super(CodexAnonDetailView, self).get_context_data(**kwargs)
context['model_name'] = model_ngettext(self.model, 1)
context['model_name_plural'] = model_ngettext(self.model, 2)
context['object_create_url'] = reverse('%s:%s_create' % (resolve(self.request.path).app_name, self.model.__name__))
context['model_list_url'] = reverse('%s:%s_list' % (resolve(self.request.path).app_name, self.model.__name__))
The beauty of Django's class based views is that you can take advantage of class inheritance to implement shared functionality
Define a class that implements the behavior you require and then inherit from both the generic view class and your mixin
class MyMixin(object):
def get_context_data(self, **kwargs):
context = super(MyMixin, self).get_context_data(**kwargs)
context['model_name'] = model_ngettext(self.model, 1)
context['model_name_plural'] = model_ngettext(self.model, 2)
context['object_create_url'] = reverse('%s:%s_create' % (resolve(self.request.path).app_name, self.model.__name__))
context['model_list_url'] = reverse('%s:%s_list' % (resolve(self.request.path).app_name, self.model.__name__))
return context
class MyCreateView(MyMixin, CreateView):
model = MyModel

Passing URL variables to a class based view

I have just started messing with class based views and I would like to be able to access variables from the URL inside my class. But I am having difficulties getting this to work. I saw some answers but they were all so short I found them to be of no help.
Basically I have a url
url(r'^(?P<journal_id>[0-9]+)/$',
views.Journal_Article_List.as_view(),
name='Journal_Page'),
Then I would like to use ListView to display all articles in the particular journal. My article table however is linked to the journal table via a journal_id. So I end up doing the following
class Journal_Article_List(ListView):
template_name = "journal_article_list.html"
model = Articles
queryset = Articles.objects.filter(JOURNAL_ID = journal_id)
paginate_by = 12
def get_context_data(self, **kwargs):
context = super(Journal_Article_List, self).get_context_data(**kwargs)
context['range'] = range(context["paginator"].num_pages)
return context
The journal_id however is not passed on like it is in functional views. From what I could find on the topic I read I can access the variable using
self.kwargs['journal_id']
But I’m kind of lost on how I am supposed to do that. I have tried it directly within the class which lets me know that self does not exist or by overwriting get_queryset, in which case it tells me as_view() only accepts arguments that are already attributes of the class.
If you override get_queryset, you can access journal_id from the URL in self.kwargs:
def get_queryset(self):
return Articles.objects.filter(JOURNAL_ID=self.kwargs['journal_id'])
You can read more about django’s dynamic filtering in the docs.

What is the difference between using TemplateView and ListView in Django?

In the database, I have a set of questions. I want to display every question in a collapsible item as a list. Previously I used TemplateView:
class questionmanager(TemplateView):
template_name = 'questionmanager.html'
questions = Question.objects.all()
def get_context_data(self, **kwargs):
context = ({
'questions': self.questions,
})
return context
Then, I read that using ListView is better practice to represent a list of objects. Then I changed my class to this:
class QuestionListView(ListView):
model = Question
def get_context_data(self, **kwargs):
context = super(QuestionListView, self).get_context_data(**kwargs)
return context
In the old template I used this for loop:
{% for question in questions %}
I thought I wouldn't need to use a for loop when I use ListView instead of TemplateView; but I couldn't list the items without a for loop. I found an example here, and it seems to me, the only difference is that in the for loop we use object_list ( {% for question in **object_list** %}) instead of using argument that we pass in the context.
I really don't see so much difference between using TemplateView and ListView - after spending an hour on this. I'd appreciate if someone explains why using ListView instead of TemplateView is a better practice (in this case).
Thanks in advance.
For simple use cases such as this, there isn't much difference. However, the ListView in this example is much cleaner as it can be reduced to:
class QuestionListView(ListView):
model = Question
considering you aren't putting anything in the context. TemplateView's as a base view are rather rudimentary, and provide a much smaller set of methods and attributes to work with for the more complex use cases, meaning you have to write more code in such instances. If you take a look and compare both views TemplateView and ListView here, you can see the difference more clearly. Pagination is a good example, to paginate a ListView you simply set the paginate_by attribute and modify your template accordingly.
Also note, you can change the default name object_list by setting context_object_name in the 'ListView'
The major difference is that ListView is best to list items from a database called model, while TemplateView is best to render a template with no model. Both views can be very concise with different meaning.
Below is sample of a list view in it simplest form
Class SampleListView(ListView):
model = ModelName
This will give you a context variable object_list and a template name in the form ("app_name/model_name_list.html") automatically that can be used to list all records in the database.
However, the TemplateView in its simplest form is
class SampleTemplateView(TemplateView):
template_name = 'app_name/filename.html'

where to include business logic in listview Class methods

I am trying to understand Django's class based views (very new to it), especially, ListView. I am struggling to understand where the "business logic should go". Say for example, I have the following class:
#views.py
class DisplayListView(ListView):
model = Cars
template_name = "searchres_list.html"
paginate_by = '5'
context_object_name = "titles"
def get_context_data(self, **kwargs):
context = super(SearchDisplayListView, self).get_context_data(**kwargs)
# custom logic whoch spits out "now". in this example [1 -->10]
context['now'] = [1,2,3,4,5,6,7,8,9,10]
return context
It works fine and I am able to look the [1 --> 10] on my template. However, when I look at the methods available under ListView I see that I could probably include my logic in get_queryset method. So, something like:
def get_queryset(self):
# Fetch the queryset from the parent get_queryset
queryset = super(SearchDisplayListView, self).get_queryset()
# custom logic whoch spits out "now". in this example [1 -->10]
queryset = [1,2,3,4,5,6,7,8,9,10]
return queryset
So, my rather (stupid) question is (or have I got this all completely wrong!), where should the business logic ideally go:
def get_context_data
def get_queryset
Thanks for your time.
Probably the best answer to such a subjective question will be: it depends.
My personal algorithm for dealing with the situations like this is the following:
if you need to add something to the context that will be passed to the template, then you don't have a choice actually, because in get_queryset method you can only modify the queryset for your ListView. So I use get_context_data in this case.
but if you're going to perform some dynamic queryset modifications, let's say your view can operate on similar model classes and the actual class is determined by the arguments passed into the view, then probably you need to overwrite get_queryset method.
Hope I gave you some insights on the topic :)

Best practice for static page elements in django

I have some page elements that don't change often and are displayed on every page like some adbars, footer content and such.
I want to change settings for this elements in my admin interface, so I have models for them.
Is there a best practice in django to deal with these elements?
Not really, no. You're describing a singleton pattern, so you might want to implement a singleton model type:
class SingletonModel(models.Model):
class Meta:
abstract = True
def save(self, *args, **kwargs):
self.id = 1
super(SingletonModel, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
pass
That will ensure that any model that inherits from that class can only ever have one member and that it can't be deleted. Other than that, I would suggest combining everything into just one model called something like SiteSettings with fields for header, footer, etc, instead of separate model for each.
You could use a context processor to add them to the context and use a simple caching mechanism so you don't have to hit the db every time like, http://eflorenzano.com/blog/2008/11/28/drop-dead-simple-django-caching/
Hard to answer - what exactly are you asking?
You can display these models in your base template. You can use caching to cut down on database calls.