Adding frequently used context objects to a view in Django
I have several Django apps within a single project. What I am running into is that I often tend to add the same object(s) to the render call that renders a particular screen.
In this example below, I have a view that displays a form with a dropdown of categories that you can choose from. Now I need to add these categories every time I display the create.html page. This is simplified, but imagine I have 6 more views that could potentially show the create.html page, all of them have to remember to add the categories array.
def createmeeting(request):
if request.method == "POST":
categories = MeetingCategory.objects.all()
// Some error checking, omitted for this example
error_msg = "invalid content"
if error_msg:
return render(request, "meetings/create.html",
{
"categories": categories,
"error_msg": error_msg,
})
else:
// Create the meeting here, omitted for this example
return redirect("/meetings/profile/")
else:
categories = MeetingCategory.objects.all()
return render(request, "meetings/create.html",
{
"categories": categories
})
Is there a better way of handling cases like this?
You could create a context processor that will add the context to all views in your app like here: https://docs.djangoproject.com/en/5.0/ref/templates/api/#writing-your-own-context-processors
You could always add an if statement:
if request.path.startswith(("path1", "path2", "xxx"))
to prevent it being added to all views
If you go over to using class-based views, you can put the common code into a Mixin class. The Mixin class would look like this:
class MeetingCategoriesMixin( object):
def get_context_data( self, **kwargs):
context = super().get_context_data( **kwargs)
context['categories'] = MeetingCategory.objects.all()
return context
and your view (which could be a FormView
or UpdateView
or CreateView
or even just a TemplateView
)
class MyViewWithCategories( MeetingCategoriesMixin, FormView):
form_class = MyFormClass
template_name = 'meetings/create.html'
def get_success_url(self):
return reverse( 'meetings:profile', kwargs={ ...})
def form_valid( self, form):
# use the valid data in the form here
# return super().form_valid( form) # or I prefer explicitly,
return HttpResponseRedirect( self.get_success_url() )
My opinionated view is to use function-based views only for cases where a standard class-based view really is too hard (and note that if you are processing a form, you can do absolutely anything in form_valid()
)
( Semi-obligatory plug for classy class-based views )