'Practical' tips for working with Django

Everything I did building the content management system for this Web site was wrong.

Actually, that might be an overstatement since this Web site works quite well (better than it did in Movable Type). But in the course of building a new Django content management system (CMS) that will drive the new, soon-to-be-launched Young Professionals of Knoxville Web site, I’ve learned a lot of useful techniques.

Much of my new-found knowledge is due to Django Release Manager James Bennett’s wonderful book “Practical Django Projects.”

Custom managers

One of the critical needs for the new YPK site is the posting and display of events. At first, I figured this would require a standard model with the following fields:

  • slug
  • name
  • location (ForeignKey to Location subclass)
  • description
  • event date
  • start time
  • finish time
  • attire (With two options: formal and casual)
  • category (ForeignKey to Category app)

But then I realized that I would need a way to filter out events that are no longer current — who wants to view old events?

That’s where custom mangers in models come into play:

class CurrentManager(models.Manager):
    def get_query_set(self):
    return super(CurrentManager, self).get_query_set().filter(event_date__gte=datetime.date.today())

This allows me to filter all events whose date is greater than or equal to the current date. I then add the following to my model:

class Event(models.Model):
    ...
    objects = models.Manager()
    current = CurrentManager()

And in my project urls.py, I can return the following queryset:

event_info_dict = {
    'queryset': Event.current.all(),
    'date_field': 'event_date',
    'allow_future': True,
}

No expired events will be displayed for that view.

I’m using the same technique to filter only press releases with a status of “live” for my news app. This would work well for blogs that have both “editing” and “live” status choices for entries.

Wrapping generic views

Another very useful technique in Django that plays off the custom manager is that of wrapping generic views with additional functions in another view.

For the YPK home page, I needed a way to pass extra context into the direct_to_template simple generic view without things getting caught in the queryset cache.

I created a new view — the home page displays both current events and live press releases — that contains the following:

from django.views.generic.simple import direct_to_template
from ypknox.apps.events.models import Event
from ypknox.apps.news.models import PressRelease

def home_page(request):
    return direct_to_template(
    request,
    extra_context={'event_list': Event.current.all()[:4], 'pressrelease_list': PressRelease.live.all()[:6]},
    template = 'home.html',
)

I knew I only needed four current events, and six live press releases, which is why I’m limiting the queries in this manner.

Now I can use the following on my home.html template to get the latest four current events:

{% for event in event_list %}
    {{ event.name }}
{% endfor %}

I’m also using this technique of wrapping generic views to reduce the amount of code needed to get live press releases or current events for my Category app (both detail and list views).

Changing text to HTML before rendering the template

This should have been a no-brainer.

Since I’m using the Django “TextField” option in several of my app models, I need a way of converting the markup language from text to HTML. Prior to reading Bennett’s book, I was doing this on the template with the markdown filter.

But I’ve learned since that this is an intensive process that needs to only be done once, and stored in the database for retrieval.

Here’s what I’m doing now (assumes Python Markdown module is installed):

from markdown import markdown

class PressRelease(models.Model):
    ...
    summary = models.TextField()
    summary_html = models.TextField(editable=False, blank=True)

def save(self):
    self.summary_html = markdown(self.summary)
    super(PressRelease, self).save()

This applies the markdown filter when saving the object in the database, and populates the summary_html field with the marked-up text. Then, on my template, I simple call the summary_html like this:

{{ object.summary_html|safe }}

The safe filter is applied because I know the markup is OK to be applied with encoding for security reasons.

There are a lot more Django tips I’m picking up as I finish the new YPK site. I’ll post those, with a link to the finished site when it’s complete.

In the meantime, please share your thoughts on these tips, or others like them, in the comments.

UPDATE (8/12/08): There was an error in the model code snippet showing the manager within the model class. This has been fixed. I’ve also added a way to show how you can still get all of the events, not just current events, using objects = models.Manager() or events.objects.all().

Read full article at “Entries for Django tag | patrickbeeson.com”

Leave a comment