Django templatetags
Wednesday, 26th November, 2008 // 11:31 p.m.Tagged: context , django and templatetags
Django template tags are a great boon to developers to perform last minute processing in templates. We often encounter situations where data returned from a view needs further processing, in such cases we can write a django template tag and bring the power of python processing right into template(HTML) level. I personally think django template tags is the best and most striking feature of django.
Yes, as a developer who spent nearly an year on django I think ability to perform something right at template level is amazing. At first I felt that template tag is something complicated and of my reach. As time went by I started to write simple template tags.
from django.utils.dateformat import format def datecomp(date, arg=None): if not date: return '' delta = datetime.date.today() - date if delta == datetime.timedelta(0): result = 'TODAY' elif delta == datetime.timedelta(1): result = 'YESTERDAY' else: result = format(date, arg) return result
When you pass a datetime field to this template tag it returns TODAY/ YESTERDAY or a formatted datetime field. Here we can see that this tag clearly return a value back to the template. But most of the template tags I have seen on http://djangosnippets.org set a context variable in the templatetag class and return '' (nothing).
Well what does it matter if the intended result is returned or set in a context variables?
It does n't really matter in most of the cases but there are a few cases where return would be useful.
Recently I have tried using django-faves. a generic favorite application for django. There are a few template tags which are very helpful while using faves app. One of the template tag is used to check if a particular object is favorite of a user. This is very important and useful tag which determines whether to show link to favorite or link to unfavorite.
Check out this template tag (get_fave) which sets a context variable 'varname' (passed by user).
I have a list of a objects displayed on a page with their associated favorite/unfavorite links. The get_fave templatetag first tries to check if the object and user exists in the Fave model. If the combination exists it returns the Fave model objects in the context or it does n't do anything.
Reason: The template tag tries to find a match in the Fave model. Suppose the first object returns True and the following objects do not exist in the model but it does n't return false. We are setting the context only if the object exists.
In such the debugging becomes hard. I personally return values from the template tag in to the template and use it rather than set the context in the template tag. Debugging becomes harder.
{% get_fave by request.user on object of type favorites as fave %} {% if fave %} //link to favorite {% else %} //link to unfavorite
When we use this logic to determine whether an object should be favorite or not it fails.
try: Fave.objects.active().get(type=fave_type, user=user, content_type=content_type, object_id=object.id) return True except: return False
We can set the context variable to True/ False as well. Either would work but return would be easier to debug.
Comment Form
3 comments:
001// Vince Jay// Thursday, 27th November, 2008, 11:12 a.m.
Whenever I encounter a situation where i'm forced to write a template tag I'm taking a deep breath. Things that are simple in a view like perform filtering on a reverse relationship queryset become yet another template tag. It always seems to be a struggle whether to complicate the view part or to complicate the template with hard to debug complex template tags which always seem to duplicate code that could and should have been put elsewhere.
002// Yashh// Thursday, 27th November, 2008, 11:51 a.m.
@Vince - I know that writing a template tag is not a preferred appraoch to a normal django user. I had difficulty approaching template tags.
After reading this post I got a better idea on approaching a template tag. Also I dug into the django's default template tags and observed how they work.
I personally prefer to put most of the logic in a view. But if you feel that you need to use that logic more than once make it a template tag. That way the dry principle holds.
003// Stephen DeGrace// Thursday, 27th November, 2008, 6:18 p.m.
Pure MVC architecture creates a problem for many websites. A real web site may have not only main content, but lots of little "widgety" content, like for example calendars and polls in a sidebar. For MVC to be elegant and not overly complicated, the view should handle the logic for the main content and push the required data into the template - it should be specific. This conflicts with the needs of many if not most "real" sites.
If your site has a bunch of stuff that could appear with any or all kinds of content, such as dynamically generated navigation and sidebar widgets, then your alternatives are to handle the widgety stuff that needs access to models via some kind of separate callback from the template (implemented as template tags in Django), or else for each and every view to contain all of the logic necessary to render every kind of content that will appear with the main content, even if it is not directly related. Your views then bloat, contain a lot of repetition from view to view, and your apps are much less portable because they become very dependent on the context of the layout and elements present in your specific website. Changes to the website need repetitive changes to many views, and apps become highly interdependent for no reason or else fail to separate content neatly into kinds.
Although using template tags to have the template directly get data from models violates the purity of MVC (MVT?), for real web sites it is much more practical. A sign that you're probably on the right track with template tags is that it creates much more architectural elegance and much less repetition. Apps remain very specific and portable, and logic to retrieve and process for display side content is in one place, the template tag, not in fifty places, every conceivable view. And the template tags themselves are very portable.
You can definitely go too crazy with template tags, but they're actually really easy to write. The only part that's mind bending is if you want to create tags that work together so you need to use the parser. Then you need to really grasp how template parsing and rendering works. A tip: the Django site documentation is not totaly up to scratch if you want to do something complex, although it gives a great intro. The actual source code has great documentation in the doc strings. Don't be afraid to dig into the source, sometimes it can really answer your questions.
I'll say one thing though: IMO, doing something with template tags and models that has side effects on the database is Evil. Templates should get, they should not put, post or delete.