0

I have a Django 1.6 application using Postgres 9.3. Every template for every view on the site will extend one or the other of two templates. One template "anon.html" will display a minimal page header on all pages a user who is not signed in can view (e.g. during the signup process when the user doesn't have an account yet). The second "auth.html" template is extended in every template that is displayed when a logged-in user is viewing a page. This template displays a header containing links such as "Show Members", "Messages", "Account" and so forth. Any view that renders this template will be prefaced with the @login_required decorator. How do I execute a Django database query each time a user requests a page that requires them to be logged in (in other words), when I render the "auth.html" template? If the user has new messages, I want to be able to change the "Messages" link in the auth.html template header to say "New Messages". This query has to run before the rest of the page is rendered and I don't want to put the query in every view.

Thanks!

Jim
  • 13,430
  • 26
  • 104
  • 155
  • Why does the query have to run before the rest of the page is rendered? – Daniel Robinson Jan 20 '15 at 22:54
  • Because I need to modify a link in the page header which is displayed to every logged-in user. The page header is rendered before each page is rendered because it is included as a part of a template that is exteneded by every other template. The page header's HTML is not included in the templates for each individual page. Rather it resides in a separate HTML file that each page template extends (i.e. includes). – Jim Jan 20 '15 at 23:00
  • The page header won't be rendered until the whole page is rendered, so you can include references to variables from your context (such as `user`) in it. I explain how in more detail in my answer. – Daniel Robinson Jan 20 '15 at 23:06

1 Answers1

2

Assuming you're using the django.core.context_processors.auth context processor, your template has access to the user object.

So if your User model has a has_messages() method that returns True when the user has messages and False if they don't, you can simply put in the following logic into your auth.html template:

{% if user.has_messages %}
    ...
{% else %}
    ...
{% endif %}

If you are using a proxy model rather than a custom User model, you will need to write a custom context processor that puts that proxy model into the template context. It should look something like this:

from models import UserProxy

def add_proxy_user(request):
    if request.user.is_authenticated():
        return {"proxy_user": UserProxy.objects.get(pk=request.user.pk)}
    else:
        return {"proxy_user": request.user}

Make sure you add it to your TEMPLATE_CONTEXT_PROCESSORS in your settings.py. Then you will have to use {{ proxy_user.has_messages }} in your template.

Community
  • 1
  • 1
Daniel Robinson
  • 3,347
  • 2
  • 18
  • 20
  • This doesn't work. I added the code exactly has you wrote it above into my auth.html template and then I added a 'has_messages' method to my UserProxy proxy model which extends the User model. I put a set_trace( ) statement in the method to see if it's being run but it's not. – Jim Jan 21 '15 at 00:14
  • It seems like this may not work with proxy models. I'll update my answer to cover that. – Daniel Robinson Jan 21 '15 at 00:23
  • Thanks Daniel for your updated code sample but where does that code go and where is it called from? It looks like code that goes in a view (since its input is the request object). I'm trying to have to avoid adding the same code to every view that uses the login decorator. – Jim Jan 21 '15 at 01:29
  • It's called a context processor. It goes in its own file (myapp.context_processors, say). You then add an entry to TEMPLATE_CONTEXT_PROCESSORS in your settings.py referring to it. It will then be run every time you render a template, and will put a {{ proxy_user }} variable in the template's context that you can access from the template. – Daniel Robinson Jan 21 '15 at 01:34