1. Skip to navigation
  2. Skip to content

This Week in Django 5 - 2008-01-06

This Week in Django is a weekly podcast about all things Django.

This week Brian Rosner joins me once again. We discuss the Akita interview of Adrian Holovaty, a few changesets, the Queryset Refactor branch, a Tip of the Week, and a few questions from the IRC Channel.

Please see the Show Notes below for all the pertinent information and links

Downloads

AAC Enhanced Podcast (28.2 MB, 58:31, AAC)

MP3 Edition (26.8 MB, 58:31, MP3)

The Enhanced Podcast version contains screenshots and easy access links to all of the items I discuss throughout the podcast.

Feeds Available

This Week in Django – AAC Edition

This Week in Django – MP3 Edition

Show Notes

Big News (1:08)

Tracking Trunk (8:12)

  • Changeset (6981) – Made the {% for %} tag a bit more efficient by creating a single context dictionary rather than recreating it each time through the loop.
  • Changeset (6998) – added a last filter, which returns the last item in a list.
  • Changeset (7001) – Session bug in odd cases where sessions kept being created in the database
  • Changeset (6996) – Reverted ‘regroup’ template tag changes from Changeset 6956 because it didn’t work when using a filter that had a parameter with spaces in it.

Branching & Merging (17:59)

Community Catchup (33:28)

  • – Google Groups discussion about not getting a nice error page when an exception occurs in the middleware. A patch is forthcoming.

Tip of the Week (42:33)

This week’s Tip of the Week comes from Brian Rosner and involves using custom Managers to simplify your filters and keep things DRY.

Each model has a Manager instance associated with it. It is typically accessed through MyModel.objects. Django lets you change this to allow you to have customized methods in objects or even add more Manager instances to your model.

Let’s take a look at a good use case for using your own manager. Here is a very familiar models.py you might have created:


from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    active = models.BooleanField(default=False)

Now lets say I need to get all the active products a lot in my code. Well to accomplish this now I would execute the following code:


Product.objects.filter(active=True)

This will give me all the products that are currently active. Well lets simplify this by using a custom manager. Lets add some code to our model:


from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    active = models.BooleanField(default=False)

    objects = models.Manager()
    active_objects = ActiveProductManager()

We have now added objects and active_objects. It is critical that you explicitly assign objects since it will cause some confusion to Django. However, this is nice to see that you can just as easily change out the object that sits behind the objects property of the class. Now lets see the code in the ActiveProductManager@ class:


class ActiveProductManager(models.Manager):

    def get_query_set(self):
        queryset = super(ActiveProductManager, self).get_query_set()
        return queryset.filter(active=True)

Make sure ActiveProductManager is defined before calling it in the Product model. If you have a lot of manager classes in the models.py it might be a good idea to place them in a managers.py file and import them at the top of models.py.

Ok, so in the ActiveProductManager class above we are overriding the get_query_set method to provide our own query set to use by default by the manager. To get a better idea of how the Manager class works check out the source code. It is very straight-forward. Now we have enabled ourselves to execute this line of code to get active products:


Product.active_objects.all()

You can also perform any other queryset filtering, exluding, etc.. since it is just a regular queryset being passed back.

IRC Ad Naseum (49:22)

How can I get the current date/time to be automatically added when I save a new record or update a record?

  • auto_now and auto_now_add are on their way out. See and .
  • Use the default option when defining the model
  • Django Documentation on default

import datetime
created_at = models.DateTimeField(default=datetime.datetime.now)
  • Do not forget to use a callable. In other words, don’t put the ending parenthesis on the now otherwise all your objects will get the same time when the class was parsed.
  • If you need to update the datetime every time then override the save method.
  • Django Documentation on Overriding the Save Method

def save(self, **kwargs):
    """override save to set defaults""" 
    if self.pk:
        self.updated_at = datetime.datetime.now()

    super(Post, self).save(**kwargs)

How can I override ModelForms field definitions? Such as changing the widget or specifying field attributes?

  • Django Documentation on Overriding Default Field Types
  • Given a ModelForm that doesn’t define any fields, everything will be the default.
  • If you define a field in your ModelForm class that has the same name as one that would be auto-generated it will override the default field.
  • You can also override the __init__ but I would only do that if you need to make dynamic runtime type modifications.
  • Django Screencast 4: NewForms Personalization

Thank You! (58:05)


Discussion