View decorator for common navigation elements?

48 views
Skip to first unread message

Victor Hooi

unread,
Sep 29, 2011, 8:59:11 PM9/29/11
to django...@googlegroups.com
Hi,

We have a common navigation bar on nearly every page (view) that contains a dropdown - this dropdown is populated with items from a database table. This dropdown also has AJAX behaviour attached to it.

I'm thinking I can create a decorator that will retrieve the list from the database, and return a Python list

We can then wrap every single view in this decorator, and then pass the list to the template for rendering.

Firstly - is there a more elegant alternative, rather than wrapping every single view in this decorator? (Middleware? Or is that a poor fit here? Anything else?).

And secondly - are there are any performance issues here? We're making database calls with every single view, just to get a list for a navigation dropdown. Smarter way?

I know I can use the caching middleware to cache entire pages, or even template fragments - but how about caching a single list() like this? What are other methods people are using to tackle this?

Cheers,
Victor

Alex Chan

unread,
Sep 29, 2011, 9:27:37 PM9/29/11
to django...@googlegroups.com
Hi Victor,

I think this is a very good question.  I've been considering what the best approach would be and decided on either using a decorator as you've mentioned or implementing class based views.  You can create base view classes that load common data for the different types of pages.  You would then have specific views subclass one of the base view classes to inherit the loading of the common data while acting on data specific to their view.

I'm curious if anyone else has any opinions or experiences loading common page elements in a clean and DRY manner.

--
Alex

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/8cKewo2DudcJ.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Luis Morales

unread,
Sep 30, 2011, 6:46:04 AM9/30/11
to Django users
wouldn't a template tag work best in a case like this?

something like {% NavBar %} or {% GetNav NavName %}

that way you can have your own cache code inside you template tag
code, like storing the database result into memcached or redis and
avoid a relational db call each page. them you you modify you
navigation data model you can you invalidate the cache and recreate
it. it will also be a lot simplier to reuse in other projects as you
wont have to inlcude a decorator on each view.

Victor Hooi

unread,
Sep 30, 2011, 5:47:15 PM9/30/11
to django...@googlegroups.com
heya,

I do like the idea of just including a custom template tag =).

Hmm, can custom template tags interact with models or query the database like that?

Firstly, Is it possible, and secondly, is it considered good practice? 

Cheers,
Victor

colinta

unread,
Oct 1, 2011, 11:22:08 AM10/1/11
to Django users
This post is particularly well timed, since I have the exact same
question. I'm excited to say the company has, after many years, been
convinced to stop working on our internal PHP framework and we chose
django as its replacement (in sad news, I was the main dev on that
framework, and poured my heart and many long nights into it. but it's
PHP code, so good riddance)

One nifty thing it could do was "auto-prepare" elements on a page,
much in the style of "pull-style" frameworks that call hooks/callbacks
based on the *view*, rather than "pushing" data onto the page. our
framework supported both styles, but django seems to be distinctly
"push" based. So I miss being able to just add an
"autoprepareTopNav()" method to a parent controller class, and have it
automatically called whenever the top-nav element was outputted.

BUT, the "common elements" problem strikes me as one of those
"certainly this has been done before" problems, and I would love to
know what the accepted django-ic solution is. My coworker, who is
more versed in django & python, wrote a context processor to fetch top-
nav and footer pages. But since it's a CP, it gets called on *every*
page, not just those that need it. _I'd_ rather it not execute except
on those pages that explicitly need that data.

I played with a view-decorator pattern that had view methods returning
*either* a response object or a (template, dict) tuple that could be
passed up the chain to include other view-method-like-decorators, and
they would add their data — in much the same way that Victor describes
here.

The benefit to that approach is that if you have *multiple* elements
that use *a common set* of data (for instance, on a site I'm working
on now we've got a category dropdown that appears in multiple places -
the top nav search, a search callout, and on the search results
page). I should not fetch this category list multiple times, and
template tags would not alleviate that, unless I throw in some global
mechanism where I can look for the data. Are class-based views the
logical solution?

Okay, so, a question does emerge. I think template tags are the right
answer here. How do I write three template tags that all use a common
set of data?

Victor Hooi

unread,
Oct 2, 2011, 7:07:15 PM10/2/11
to django...@googlegroups.com
heya,

This SO post seems to suggest that data and template tags shouldn't mix...


Not sure how I feel about that myself - I see the philosophical argument behind it, but I don't see another more efficiently creating common page elements (like my category dropdowns).

Also, if you look at James Bennett's posts here:


His code actually *does* interact with the database, as does the blog post here (http://www.webmonkey.com/2010/02/use_templates_in_django/#Roll_your_own_template_tags).

Also, as an aside, each link on our category dropdown is bound to a JS click event - not sure how this would tie in with the custom template tag - separate tag for that part of it?

Cheers,
Victor

Thomas Orozco

unread,
Oct 3, 2011, 3:52:16 AM10/3/11
to django...@googlegroups.com

Maybe you can use template inheritance and have the base template access the data through, alternatively, template filters or instance methods?

To make those work, you can take advantage of the existing template processors (notably the auth one).

If you want to not have the topnav on a particular page, you can put it in a block and replace the block with nothing.

> --
> You received this message because you are subscribed to the Google Groups "Django users" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/9cYeQwELEYsJ.
Reply all
Reply to author
Forward
0 new messages