4

I'm working on a project in Django.

Earlier today, I discovered the new (Django >= 1.4) assignment_tag. I immediately decided that it was just what I needed EVERYWHERE and threw some logic into one that executed a very simple query against the database and returned the resulting queryset. The function I wrapped takes an argument that allows the invoking context to specify how many results to grab, directly in the template when I am using the template tag.

It is quite convenient - I don't have to update my view when I decide this list should have 5 items, not 3 - but it seems like one of those gray areas where we aren't supposed to tread (i.e. pushing application logic into templates) when writing good, maintainable Django code.

Now, a couple of hours separated from writing the code, I'm wondering if I should scrap the assignment_tag entirely.

Code:

models.py:

class SomeObject(models.Model):
    is_active = models.BooleanField(default=False)
    (...)

templatetags/myapp_tags.py:

from django import template
from myapp.models import SomeObject

register = template.Library()

@register.assignment_tag
def get_someobjects_list(max_results=0):
    queryset = SomeObject.objects.filter(is_active=True)
    if max_results == 0:
        return queryset
    elif max_results > 0:
        return queryset[:min(max_results, queryset.count())]
    else:
        return None

templates/myapp/chunks/someobject_list.html:

{% load myapp_tags %}

{% get_someobjects_list as someobjects_list %} 
# or {% get_some_objects_list 5 as someobjects_list %} ... flexible!
{% if someobjects_list %}
<ul>
  {% for someobject in someobjects_list %}
  <li>
    <a href="{{ someobject.get_absolute_url }}">
      {{ someobject.name }}
    </a>
  </li>
  {% endfor %}
</ul>
{% else %}
<span>No someobjects exist</span>
{% endif %}

I was really excited to discover these existed - it's convenient for me in this particular case. Now that my excitement over finding a new feature has passed, it seems pretty clear that I'm misusing it. The example given in the Django docs seems like a better application of this - grabbing the string representation of current datetime, something that doesn't require a DB query. My worry is that I'm setting myself up for heartache if I start using this pattern regularly. Following the slippery slope all the way down: I'll end up not even bothering to pass a context to my templates and ALL my DB queries will be hidden away in template tags where nobody would think to look for them.

It seems the code would be cleaner if I just threw out this whole "great idea" I had when I discovered assignment_tags and created a custom model manager instead.

Are there other clean ways of accomplishing this that I am missing? Are manager methods the consensus best way among Django developers?

chucksmash
  • 5,777
  • 1
  • 32
  • 41
  • In this situation, I would have your view store `someobjects_list` into the context for you - then you don't need the templatetag, and your query will live somewhere that makes sense (either in your views, or in your models on a custom manager). – girasquid May 28 '13 at 17:18

1 Answers1

2

assignment template tags are especially helpful if you need to get some information into the template context for a few pages of a website, but don't want to (or can't) put the info into every view on the website, and don't want to or can't rely on a context processor.

they basically guarantee that your information will be available in the template.

Collin Anderson
  • 14,787
  • 6
  • 68
  • 57