Table Of Contents

Previous topic

Urls

Next topic

Views

This Page

Models

Multiple managers

A Model class can have multiple managers, depending upon your needs. Suppose you do not want to display any object on your site which is unapproved(is_approved = False in your Model).:

class ModelClassApprovedOnlyManager(models.Manager):
    def get_query_set():
        self.get_query_set().filter(is_approved = True)

class ModelClass(models.Model):
    ...
    is_approved = models.BooleanField(default = False)

    all_objects = models.Manager()
    objects = ModelClassApprovedOnlyManager()

If you use multiple managers, the first manager should be the default manager. This is as the first manager is accesible as ModelClass._default_manager, which is used by admin to get all objects.

Hierarchical Relationships

You may want to model hierarchical relationships. The simplest way to do this is:

class ModelClass(models.Model):
    ...
    parent = models.ForeignKey('ModelClass')

This is called adjacency list model, and is very inefficient for large trees. If your trees are very shallow you can use this. Otherwise you want to use a more efficient but complex modeling called MPTT. Fortunately, you can just use django-mptt.

Singleton classes

Sometimes you want to make sure that only one Object of a Model can be created.

Logging

To make sure, when an object is create/edited/deleted, there is a log.

Audit Trail and rollback

When an object is modified or deleted, to be able to go back to the previous version.

Define an __unicode___

Until you define an __unicode__ for your ModelClass, in Admin and at various other places you will get an <ModelClass object> where the object needs to be displayed. Define a meaningful __unicode__ for you ModelClass, to get meaningful display. Once you define __unicode__, you do not need to define __str__.

Define a get_absolute_url()

get_absolute_url is used at various places by Django. (In Admin for “view on site” option, and in feeds framework).

AuditFields

Say you want to keep track of when was an object created and uodated. Create two DateTimeFields with auto_now and auto_now_add.:

class ItemSold(models.Model):
    name = models.CharField(max_length = 100)
    value = models.PositiveIntegerField()
    ...
    #Audit field
    created_on = models.DateTimeField(auto_now_add = True)
    updated_on = models.DateTimeField(auto_now = True)

Now you want, created_by and updated_by. This is possible using the threadlocals(http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser) technique, but since we [do not want](http://www.b-list.org/weblog/2008/dec/24/admin/) to do that, we will need to pass user to the methods.:

class ItemSold(models.Manager):
    def create_item_sold(self, user, ...):


class ItemSold(models.Model):
    name = models.CharField(max_length = 100)
    value = models.PositiveIntegerField()
    ...
    #Audit field
    created_on = models.DateTimeField(auto_now_add = True)
    updated_on = models.DateTimeField(auto_now = True)
    created_by = models.ForeignKey(User, ...)
    updated_by = models.ForeignKey(User, ...)

    def set_name(self, user, value):
        self.created_by = user
        self.name = value
        super(ItemSold, self).save()

    ...

objects = ItemSoldManager()

Working with denormalised fields

Working with child tables.

Say you want to keep track of number of employees of a department.:

class Department(models.Model):
    name = models.CharField(max_length = 100)
    employee_count = models.PositiveIntegerField(default = 0)


class Employee(models.Model):
    department = models.ForeignKey(Department)

One way to do so would be to override, save and delete.:

class Employee(models.Model):
    ...

    def save(self):
        if not self.id:
            #this is a create, not an update
            self.department.employee_count += 1
            self.department.save()
        super(Employee, self).save()

    def delete(self):
        self.department.employee_count -= 1
        self.department.save()
        super(Employee, self).save()

Other option would be to attach listeners for post_save and post_delete. #TODO

Abstract custom queries in Manager methods.

If you have some complex Sql query, not easily representable via Django ORM, you can write custom Sql. These should be abstracted as Manager methods.

blog comments powered by Disqus