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.
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.
Sometimes you want to make sure that only one Object of a Model can be created.
To make sure, when an object is create/edited/deleted, there is a log.
When an object is modified or deleted, to be able to go back to the previous version.
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__.
get_absolute_url is used at various places by Django. (In Admin for “view on site” option, and in feeds framework).
You want only one canonical representation of your urls. This should be in urls.py
If you write a class like:
class Customer(models.Model)
...
def get_absolute_url(self):
return /customer/%s/ % self.slug
You have this representation at two places. You instead want to do:
class Customer(models.Model)
...
@permalink
def get_absolute_url(self):
return ('customers.detail', self.slug)
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 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
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.