Finished proofreading docs/model-api.txt
git-svn-id: http://code.djangoproject.com/svn/django/trunk@2833 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
a79cbb5fe8
commit
a8ccdd0fcd
|
@ -1298,16 +1298,22 @@ user searches for ``john lennon``, Django will do the equivalent of this SQL
|
|||
Managers
|
||||
========
|
||||
|
||||
The Manager is the interface through which database query operations
|
||||
are provided to Django applications. At least one Manager exists for
|
||||
every model in a Django application.
|
||||
A ``Manager`` is the interface through which database query operations are
|
||||
provided to Django models. At least one ``Manager`` exists for every model in
|
||||
a Django application.
|
||||
|
||||
By default, Django will add a Manager with the name of ``objects`` to
|
||||
every Django model. However, if you wish to use ``objects`` as a field
|
||||
name, or if you wish to use a name other than ``objects`` for the Manager,
|
||||
you can rename the Manager on a per-model basis. To rename the Manager
|
||||
for a given class, define a class attribute of type models.Manager()
|
||||
on that model. For example::
|
||||
The way ``Manager`` classes work is documented in the `Retrieving objects`_
|
||||
section of the database API docs, but this section specifically touches on
|
||||
model options that customize ``Manager`` behavior.
|
||||
|
||||
Manager names
|
||||
-------------
|
||||
|
||||
By default, Django adds a ``Manager`` with the name ``objects`` to every Django
|
||||
model class. However, if you want to use ``objects`` as a field name, or if you
|
||||
want to use a name other than ``objects`` for the ``Manager``, you can rename
|
||||
it on a per-model basis. To rename the ``Manager`` for a given class, define a
|
||||
class attribute of type ``models.Manager()`` on that model. For example::
|
||||
|
||||
from django.db import models
|
||||
|
||||
|
@ -1315,38 +1321,118 @@ on that model. For example::
|
|||
#...
|
||||
people = models.Manager()
|
||||
|
||||
In this example, ``Person.objects.all()`` will generate an error, but
|
||||
``Person.people.all()`` will provide a list of all ``Person`` objects.
|
||||
Using this example model, ``Person.objects`` will generate an
|
||||
``AttributeError`` exception, but ``Person.people.all()`` will provide a list
|
||||
of all ``Person`` objects.
|
||||
|
||||
Managers can also be customized. This is achieved by extending the
|
||||
base Manager class, and instantiating the new Manager on your model.
|
||||
There are two reasons that you may want to customize a Manager: firstly,
|
||||
to add utility methods to the Manager, and secondly, to modify the
|
||||
initial Query Set provided by the Manager.
|
||||
Custom Managers
|
||||
---------------
|
||||
|
||||
To modify the initial Query Set provided by a Manager, override the
|
||||
``get_query_set()`` method to return a Query Set with the properties
|
||||
you require. For example::
|
||||
You can use a custom ``Manager`` in a particular model by extending the base
|
||||
``Manager`` class and instantiating your custom ``Manager`` in your model.
|
||||
|
||||
class PersonManager(models.Manager):
|
||||
# Add some custom behavior to the Manager
|
||||
def move_house(self):
|
||||
# Some logic to help a person move house
|
||||
There are two reasons you might want to customize a ``Manager``: to add extra
|
||||
``Manager`` methods, and/or to modify the initial ``QuerySet`` the ``Manager``
|
||||
returns.
|
||||
|
||||
# Modify the initial Query Set provided by the manager
|
||||
Adding extra Manager methods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Adding extra ``Manager`` methods is the preferred way to add "table-level"
|
||||
functionality to your models. (For "row-level" functionality -- i.e., functions
|
||||
that act on a single instance of a model object -- use _`Model methods`, not
|
||||
custom ``Manager`` methods.)
|
||||
|
||||
A custom ``Manager`` method can return anything you want. It doesn't have to
|
||||
return a ``QuerySet``.
|
||||
|
||||
For example, this custom ``Manager`` offers a method ``with_counts()``, which
|
||||
returns a list of all ``OpinionPoll`` objects, each with an extra
|
||||
``num_responses`` attribute that is the result of an aggregate query::
|
||||
|
||||
class PollManager(models.Manager):
|
||||
def with_counts(self):
|
||||
from django.db import connection
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("""
|
||||
SELECT p.id, p.question, p.poll_date, COUNT(*)
|
||||
FROM polls_opinionpoll p, polls_response r
|
||||
WHERE p.id = r.poll_id
|
||||
GROUP BY 1, 2, 3
|
||||
ORDER BY 3 DESC""")
|
||||
result_list = []
|
||||
for row in cursor.fetchall():
|
||||
p = self.model(id=row[0], question=row[1], poll_date=row[2])
|
||||
p.num_responses = row[3]
|
||||
result_list.append(p)
|
||||
return result_list
|
||||
|
||||
class OpinionPoll(models.Model):
|
||||
question = models.CharField(maxlength=200)
|
||||
poll_date = models.DateField()
|
||||
objects = PollManager()
|
||||
|
||||
class Response(models.Model):
|
||||
poll = models.ForeignKey(Poll)
|
||||
person_name = models.CharField(maxlength=50)
|
||||
response = models.TextField()
|
||||
|
||||
With this example, you'd use ``OpinionPoll.objects.with_counts()`` to return
|
||||
that list of ``OpinionPoll`` objects with ``num_responses`` attributes.
|
||||
|
||||
Another thing to note about this example is that ``Manager`` methods can
|
||||
access ``self.model`` to get the model class to which they're attached.
|
||||
|
||||
Modifying initial Manager QuerySets
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A ``Manager``'s base ``QuerySet`` returns all objects in the system. For
|
||||
example, using this model::
|
||||
|
||||
class Book(models.Model):
|
||||
title = models.CharField(maxlength=100)
|
||||
author = models.CharField(maxlength=50)
|
||||
|
||||
...the statement ``Book.objects.all()`` will return all books in the database.
|
||||
|
||||
You can override a ``Manager``'s base ``QuerySet`` by overriding the
|
||||
``Manager.get_query_set()`` method. ``get_query_set()`` should return a
|
||||
``QuerySet`` with the properties you require.
|
||||
|
||||
For example, the following model has *two* ``Manager``s -- one that returns
|
||||
all objects, and one that returns only the books by Roald Dahl::
|
||||
|
||||
# First, define the Manager subclass.
|
||||
class DahlBookManager(models.Manager):
|
||||
def get_query_set(self):
|
||||
return super(Manager, self).get_query_set().filter(name__startswith="Fred")
|
||||
return super(Manager, self).get_query_set().filter(author='Roald Dahl')
|
||||
|
||||
class Person(models.Model):
|
||||
#...
|
||||
objects = PersonManager()
|
||||
# Then hook it into the Book model explicitly.
|
||||
class Book(models.Model):
|
||||
title = models.CharField(maxlength=100)
|
||||
author = models.CharField(maxlength=50)
|
||||
|
||||
In this example, ``Person.objects.all()`` will only return people whose name starts
|
||||
with "Fred"; ``Person.objects.move_house()`` will also be available.
|
||||
objects = models.Manager() # The default manager.
|
||||
dahl_objects = DahlBookManager() # The Dahl-specific manager.
|
||||
|
||||
If required, you can add multiple Managers to a model. Every Manager attribute
|
||||
added to a model can be accessed and used as a manager. This is an easy way
|
||||
to define common filters types for your models. For example, the model::
|
||||
With this sample model, ``Book.objects.all()`` will return all books in the
|
||||
database, but ``Book.dahl_objects.all()`` will only return the ones written by
|
||||
Roald Dahl.
|
||||
|
||||
Of course, because ``get_query_set()`` returns a ``QuerySet`` object, you can
|
||||
use ``filter()``, ``exclude()`` and all the other ``QuerySet`` methods on it.
|
||||
So these statements are all legal::
|
||||
|
||||
Book.dahl_objects.all()
|
||||
Book.dahl_objects.filter(title='Matilda')
|
||||
Book.dahl_objects.count()
|
||||
|
||||
This example also pointed out another interesting technique: using multiple
|
||||
managers on the same model. You can attach as many ``Manager()`` instances to
|
||||
a model as you'd like. This is an easy way to define common "filters" for your
|
||||
models.
|
||||
|
||||
For example::
|
||||
|
||||
class MaleManager(models.Manager):
|
||||
def get_query_set(self):
|
||||
|
@ -1357,126 +1443,130 @@ to define common filters types for your models. For example, the model::
|
|||
return super(Manager, self).get_query_set().filter(sex='F')
|
||||
|
||||
class Person(models.Model):
|
||||
#...
|
||||
first_name = models.CharField(maxlength=50)
|
||||
last_name = models.CharField(maxlength=50)
|
||||
sex = models.CharField(maxlength=1, choices=(('M', 'Male'), ('F', 'Female')))
|
||||
people = models.Manager()
|
||||
men = MaleManager()
|
||||
women = FemaleManager()
|
||||
|
||||
... will allow end users to request ``Person.men.all()``, ``Person.women.all()``,
|
||||
This example allows you to request ``Person.men.all()``, ``Person.women.all()``,
|
||||
and ``Person.people.all()``, yielding predictable results.
|
||||
|
||||
If you are going to install a customized Manager, be warned that the first
|
||||
Manager that Django encounters in a model definition has special status.
|
||||
Django interprets the first Manager defined in a class as the default Manager.
|
||||
Certain operations use the default Manager to obtain lists of objects, so it
|
||||
is generally a good idea for the first Manager to be relatively unfiltered.
|
||||
In the last example, ``people`` is defined first - so the default Manager
|
||||
will include everyone.
|
||||
If you use custom ``Manager`` objects, take note that the first ``Manager``
|
||||
Django encounters (in order by which they're defined in the model) has a
|
||||
special status. Django interprets the first ``Manager`` defined in a class as
|
||||
the "default" ``Manager``. Certain operations -- such as Django's admin site --
|
||||
use the default ``Manager`` to obtain lists of objects, so it's generally a
|
||||
good idea for the first ``Manager`` to be relatively unfiltered. In the last
|
||||
example, the ``people`` ``Manager`` is defined first -- so it's the default
|
||||
``Manager``.
|
||||
|
||||
Model methods
|
||||
=============
|
||||
|
||||
There are a number of methods you can define on model objects to control the
|
||||
object's behavior. First, any methods you define will be available as methods
|
||||
of object instances. For example::
|
||||
Define custom methods on a model to add custom "row-level" functionality to
|
||||
your objects. Whereas ``Manager`` methods are intended to do "table-wide"
|
||||
things, model methods should act on a particular model instance.
|
||||
|
||||
class Pizza(models.Model):
|
||||
# ...
|
||||
This is a valuable technique for keeping business logic in one place -- the
|
||||
model.
|
||||
|
||||
def is_disgusting(self):
|
||||
return "anchovies" in [topping.name for topping in self.toppings.all()]
|
||||
For example, this model has a few custom methods::
|
||||
|
||||
Now, every ``Pizza`` object will have a ``is_disgusting()`` method.
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(maxlength=50)
|
||||
last_name = models.CharField(maxlength=50)
|
||||
birth_date = models.DateField()
|
||||
address = models.CharField(maxlength=100)
|
||||
city = models.CharField(maxlength=50)
|
||||
state = models.USStateField() # Yes, this is America-centric...
|
||||
|
||||
See `Giving models custom methods`_ for a full example.
|
||||
def baby_boomer_status(self):
|
||||
"Returns the person's baby-boomer status."
|
||||
import datetime
|
||||
if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31):
|
||||
return "Baby boomer"
|
||||
if self.birth_date < datetime.date(1945, 8, 1):
|
||||
return "Pre-boomer"
|
||||
return "Post-boomer"
|
||||
|
||||
.. _Giving models custom methods: http://www.djangoproject.com/documentation/models/custom_methods/
|
||||
def is_midwestern(self):
|
||||
"Returns True if this person is from the Midwest."
|
||||
return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')
|
||||
|
||||
def _get_full_name(self):
|
||||
"Returns the person's full name."
|
||||
return '%s %s' % (self.first_name, self.last_name)
|
||||
full_name = property(_get_full_name)
|
||||
|
||||
The last method in this example is a *property*. `Read more about properties`_.
|
||||
|
||||
.. _Read more about properties: http://www.python.org/download/releases/2.2/descrintro/#property
|
||||
|
||||
A few object methods have special meaning:
|
||||
|
||||
``__str__``
|
||||
Django uses ``str(obj)`` in a number of places, most notably as the value
|
||||
inserted into a template when it displays an object. Thus, you should always
|
||||
return a nice, human-readable string for the object's ``__str__``.
|
||||
-----------
|
||||
|
||||
Although defining ``__str__()`` isn't required, it's strongly encouraged.
|
||||
``__str__()`` is a Python "magic method" that defines what should be returned
|
||||
if you call ``str()`` on the object. Django uses ``str(obj)`` in a number of
|
||||
places, most notably as the value displayed to render an object in the Django
|
||||
admin site and as the value inserted into a template when it displays an
|
||||
object. Thus, you should always return a nice, human-readable string for the
|
||||
object's ``__str__``. Although this isn't required, it's strongly encouraged.
|
||||
|
||||
See `Adding str`_ for a full example.
|
||||
For example::
|
||||
|
||||
.. _Adding str: http://www.djangoproject.com/documentation/models/repr/
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(maxlength=50)
|
||||
last_name = models.CharField(maxlength=50)
|
||||
|
||||
def __str__(self):
|
||||
return '%s %s' % (self.first_name, self.last_name)
|
||||
|
||||
``get_absolute_url``
|
||||
Define a ``get_absolute_url`` method to tell Django how to calculate the
|
||||
--------------------
|
||||
|
||||
Define a ``get_absolute_url()`` method to tell Django how to calculate the
|
||||
URL for an object. For example::
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "/pizzas/%i/" % self.id
|
||||
return "/people/%i/" % self.id
|
||||
|
||||
Django uses this in its admin interface. If an object defines
|
||||
``get_absolute_url``, the object detail page will have a "View on site"
|
||||
link that will jump you directly to the object's public view.
|
||||
``get_absolute_url()``, the object-editing page will have a "View on site"
|
||||
link that will jump you directly to the object's public view, according to
|
||||
``get_absolute_url()``.
|
||||
|
||||
Also, a couple of other bits of Django, such as the syndication-feed framework,
|
||||
use ``get_absolute_url()`` as a convenience to reward people who've defined the
|
||||
method.
|
||||
|
||||
It's good practice to use ``get_absolute_url()`` in templates, instead of
|
||||
hard-coding your objects' URLs.
|
||||
hard-coding your objects' URLs. For example, this template code is bad::
|
||||
|
||||
Module-level methods
|
||||
--------------------
|
||||
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
|
||||
|
||||
If you want to add a method to the Model, rather than instances of the model,
|
||||
you can use the Python ``staticmethod`` and ``classmethod`` operators. For
|
||||
example::
|
||||
But this template code is good::
|
||||
|
||||
class Pizza(models.Model):
|
||||
# ...
|
||||
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
|
||||
|
||||
def get_pizzas_to_deliver():
|
||||
return get_list(delivered__exact=False)
|
||||
get_pizzas_to_deliver = staticmethod(get_pizzas_to_deliver)
|
||||
|
||||
Or, using Python 2.4 decorators::
|
||||
|
||||
# ...
|
||||
@staticmethod
|
||||
def get_pizzas_to_deliver():
|
||||
# ...
|
||||
|
||||
This will make the top-level ``pizzas`` module have a ``get_pizzas_to_deliver()``
|
||||
method::
|
||||
|
||||
>>> from pizza_hut.models import Pizza
|
||||
>>> Pizza.get_pizzas_to_deliver()
|
||||
[ ... ]
|
||||
|
||||
Manipulator methods
|
||||
-------------------
|
||||
|
||||
(The functionality in this section is going away soon. This documentation is
|
||||
provided only for legacy purposes at this point.)
|
||||
|
||||
Similarly, you can add methods to the object's manipulators by defining methods
|
||||
that being with "_manipulator_". This is most useful for providing custom
|
||||
validators for certain fields, because manipulators automatically call any
|
||||
method that begins with "validate"::
|
||||
|
||||
class Pizza(models.Model):
|
||||
# ...
|
||||
|
||||
def _manipulator_validate_customer_id(self, field_data, all_data):
|
||||
from django.core import validators
|
||||
from django.conf.settings import BAD_CUSTOMER_IDS
|
||||
|
||||
if int(field_data) in BAD_CUSTOMER_IDS:
|
||||
raise validators.ValidationError, "We don't deliver to this customer."
|
||||
(Yes, we know ``get_absolute_url()`` couples URLs to models, which violates the
|
||||
DRY principle, because URLs are defined both in a URLconf and in the model.
|
||||
This is a rare case in which we've intentionally violated that principle for
|
||||
the sake of convenience. With that said, we're working on an even cleaner way
|
||||
of specifying URLs in a more DRY fashion.)
|
||||
|
||||
Executing custom SQL
|
||||
--------------------
|
||||
|
||||
Feel free to write custom SQL statements in custom model methods and
|
||||
module-level methods. The object ``django.db.connection`` object represents
|
||||
the current database connection. To use it, call ``connection.cursor()`` to
|
||||
get a cursor object. Then, call ``cursor.execute(sql, [params])``
|
||||
to execute the SQL and ``cursor.fetchone()`` or ``cursor.fetchall()`` to return
|
||||
the resulting rows. Example::
|
||||
module-level methods. The object ``django.db.connection`` represents the
|
||||
current database connection. To use it, call ``connection.cursor()`` to get a
|
||||
cursor object. Then, call ``cursor.execute(sql, [params])`` to execute the SQL
|
||||
and ``cursor.fetchone()`` or ``cursor.fetchall()`` to return the resulting
|
||||
rows. Example::
|
||||
|
||||
def my_custom_sql(self):
|
||||
from django.db import connection
|
||||
|
@ -1494,12 +1584,14 @@ via a ``DELETE`` or ``UPDATE`` -- you'll need to call ``db.commit()``. Example::
|
|||
cursor.execute("DELETE FROM bar WHERE baz = %s", [self.baz])
|
||||
connection.commit()
|
||||
|
||||
``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If you're not
|
||||
familiar with the Python DB-API, note that the SQL statement in
|
||||
``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If
|
||||
you're not familiar with the Python DB-API, note that the SQL statement in
|
||||
``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters
|
||||
directly within the SQL. If you use this technique, the underlying database
|
||||
library will automatically add quotes and escaping to your parameter(s) as
|
||||
necessary.
|
||||
necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the
|
||||
``"?"`` placeholder, which is used by the SQLite Python bindings. This is for
|
||||
the sake of consistency and sanity.)
|
||||
|
||||
A final note: If all you want to do is a custom ``WHERE`` clause, you can just
|
||||
just the ``where``, ``tables`` and ``params`` arguments to the standard lookup
|
||||
|
@ -1508,32 +1600,35 @@ API. See `Other lookup options`_.
|
|||
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
|
||||
.. _Other lookup options: http://www.djangoproject.com/documentation/db_api/#extra-params-select-where-tables
|
||||
|
||||
Using models
|
||||
============
|
||||
|
||||
Once you have created your model, you have to tell Django about your new application.
|
||||
This is done by editing your settings file and adding the name of the module that
|
||||
contains your models module to the ``INSTALLED_APPS`` tuple.
|
||||
|
||||
For example, if the models for your application are contained in the module
|
||||
``project.myapp.models`` (the package structure that is created for an application
|
||||
by the ``django-admin.py startapp`` script), ``INSTALLED_APPS`` should read, in part::
|
||||
|
||||
INSTALLED_APPS = (
|
||||
#...
|
||||
project.myapp,
|
||||
#...
|
||||
)
|
||||
|
||||
Models across files
|
||||
===================
|
||||
|
||||
It's perfectly OK to relate a model to one from another module. To do this,
|
||||
just import the model module at the top of your model module. Then, just
|
||||
refer to the other model class wherever needed. For example::
|
||||
It's perfectly OK to relate a model to one from another app. To do this, just
|
||||
import the related model at the top of the model that holds your model. Then,
|
||||
just refer to the other model class wherever needed. For example::
|
||||
|
||||
from myproject.otherapp import Site
|
||||
from mysite.geography.models import ZipCode
|
||||
|
||||
class MyModel(models.Model):
|
||||
class Restaurant(models.Model):
|
||||
# ...
|
||||
sites = models.ManyToManyField(Site)
|
||||
zip_code = models.ForeignKey(ZipCode)
|
||||
|
||||
Using models
|
||||
============
|
||||
|
||||
Once you have created your models, the final step is to tell Django you're
|
||||
going to *use* those models.
|
||||
|
||||
Do this by editing your settings file and changing the ``INSTALLED_APPS``
|
||||
setting to add the name of the module that contains your ``models.py``.
|
||||
|
||||
For example, if the models for your application live in the module
|
||||
``mysite.myapp.models`` (the package structure that is created for an
|
||||
application by the ``manage.py startapp`` script), ``INSTALLED_APPS`` should
|
||||
read, in part::
|
||||
|
||||
INSTALLED_APPS = (
|
||||
#...
|
||||
'mysite.myapp',
|
||||
#...
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue