Changes between Initial Version and Version 1 of RemovingTheMagic


Ignore:
Timestamp:
Dec 6, 2005, 10:18:29 PM (18 years ago)
Author:
Adrian Holovaty
Comment:

Created page.

Legend:

Unmodified
Added
Removed
Modified
  • RemovingTheMagic

    v1 v1  
     1= Removing the magic =
     2
     3This document proposes a new, cleaner and less magical Django database API.
     4
     5== Model definition ==
     6
     7Difference: Import is from {{{django.db.models}}} instead of {{{django.core.meta}}}. This is easier to remember. {{{models}}} may not be the best name for it.
     8
     9{{{
     10#!python
     11from django.db import models
     12
     13class Person(models.Model):
     14    first_name = models.CharField(maxlength=30)
     15
     16    last_name = models.CharField(maxlength=30)
     17}}}
     18
     19Properties are allowed.
     20
     21{{{
     22#!python
     23from django.db import models
     24
     25class Person(models.Model):
     26    first_name = models.CharField(maxlength=30)
     27    last_name = models.CharField(maxlength=30)
     28
     29def _get_full_name(self):
     30    return "%s %s" % (self.first_name, self.last_name)
     31full_name = property(_get_full_name)
     32}}}
     33
     34== Database connection ==
     35
     36Old:
     37{{{
     38#!python
     39from django.core.db import db
     40cursor = db.cursor()
     41}}}
     42
     43New:
     44{{{
     45#!python
     46from django.db import connection
     47cursor = connection.cursor()
     48}}}
     49
     50This is easier to remember, clearer and more consistent.
     51
     52== API usage: Object creation ==
     53
     54Import the model class directly from the module in which it was defined. No more {{{django.models.*}}} magic.
     55
     56{{{
     57#!python
     58from myproject.people.models import Person
     59p = Person(first_name='John', last_name='Smith')
     60p.save()
     61}}}
     62
     63== API usage: Table-level functions ==
     64
     65All "table-level" functions -- ways of retrieving records tablewide rather than performing instance-specific tasks -- are accessed via a model instance's {{{objects}}} attribute. They aren't direct methods of a model object because we want to keep the "table-wide" and "row-specific" namespaces separate.
     66
     67{{{
     68#!python
     69from myproject.people.models import Person
     70p_list = Person.objects.get_list()
     71p = Person.objects.get_object()
     72}}}
     73
     74This doesn't work from an instance.
     75
     76{{{
     77#!python
     78p = Person.objects.get_object(pk=1)
     79p.objects.get_list() # Will raise an exception.
     80}}}
     81
     82If a model already has an {{{objects}}} attribute, the field-accessor attribute is renamed to {{{objects_}}}.
     83
     84{{{
     85#!python
     86class Person(models.Model):
     87    first_name = models.CharField(maxlength=30)
     88    last_name = models.CharField(maxlength=30)
     89    objects = models.TextField()
     90
     91p = Person(first_name='Mary', last_name='Jones', objects_='Hello there.')
     92p.save()
     93p.objects_ == 'Hello there.'
     94}}}
     95
     96== API usage: Overridding model methods (and pre- and post-save hooks) ==
     97
     98Proper subclassing of methods will now work, so you can subclass the automatic {{{save()}}} and {{{delete()}}} methods. This removes the need for the {{{_pre_save()}}} and {{{_post_save()}}} hooks. Example:
     99
     100{{{
     101#!python
     102class Person(models.Model):
     103    first_name = models.CharField(maxlength=30)
     104    last_name = models.CharField(maxlength=30)
     105
     106def save(self):
     107    self.do_something()
     108    super(Person, self).save(self) # Call the "real" save() method.
     109    self.do_something_else()
     110}}}
     111
     112You can even skip saving (as requested in #1014).
     113
     114{{{
     115#!python
     116class Person(models.Model):
     117    first_name = models.CharField(maxlength=30)
     118    last_name = models.CharField(maxlength=30)
     119
     120def save(self):
     121    if datetime.date.today() > datetime.date(2005, 1, 1):
     122        super(Person, self).save(self) # Call the "real" save() method.
     123    else:
     124        # Don't save.
     125        pass
     126}}}
     127
     128== API usage: Overridding table-level functions ==
     129
     130You can also override any table-level functions, such as {{{get_list()}}} or {{{get_object()}}}. Do this by creating a custom {{{models.Manager}}} subclass and passing it to your model.
     131
     132{{{
     133#!python
     134from django.db import models
     135class PersonManager(models.Manager):
     136    def get_list(self, **kwargs):
     137        # Changes get_list() to hard-code a limit=10.
     138        kwargs['limit'] = 10
     139        return super(PersonManager, self).get_list(self, **kwargs) # Call the "real" get_list() method.
     140
     141class Person(models.Model):
     142    first_name = models.CharField(maxlength=30)
     143    last_name = models.CharField(maxlength=30)
     144    class META:
     145        manager = PersonManager()
     146}}}
     147
     148== API usage: Specifying lookups ==
     149
     150Old:
     151{{{
     152#!python
     153people.get_list(first_name__exact='Adrian')
     154}}}
     155
     156New:
     157{{{
     158#!python
     159Person.objects.get_list(Person.q.first_name == 'Adrian')
     160}}}
     161
     162The old syntax will still be supported and documented, indefinitely. The new syntax will be implemented as a thin wrapper around the old syntax. See patch on #851 for implementation.
     163
     164== Other "module"-level members: Automatic manipulators and ObjectDoesNotExist exception ==
     165
     166{{{
     167#!python
     168Person.get_add_manipulator()
     169Person.get_change_manipulator()
     170Person.DoesNotExist
     171}}}
Back to Top