Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Proofread docs/db-api.txt

git-svn-id: http://code.djangoproject.com/svn/django/trunk@2820 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 227d48af1cf77947caf0ca384e62ac04afa51259 1 parent c62a014
@adrianholovaty adrianholovaty authored
Showing with 250 additions and 174 deletions.
  1. +250 −174 docs/db-api.txt
View
424 docs/db-api.txt
@@ -1032,6 +1032,30 @@ equivalent::
Entry.objects.filter(blog__id__exact=3)
Entry.objects.filter(blog__pk=3)
+Lookups that span relationships
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django offers a powerful and intuitive way to "follow" relationships in
+lookups, taking care of the SQL ``JOIN``s for you automatically, behind the
+scenes. To span a relationship, just use the field name of related fields
+across models, separated by double underscores, until you get to the field you
+want.
+
+This example retrieves all ``Entry`` objects with a ``Blog`` whose ``name``
+is ``'Beatles Blog'``::
+
+ Entry.objects.filter(blog__name__exact='Beatles Blog')
+
+This spanning can be as deep as you'd like.
+
+It works backwards, too. To refer to a "reverse" relationship, just use the
+lowercase name of the model.
+
+This example retrieves all ``Blog`` objects who have at least one ``Entry``
+whose ``headline`` contains ``'Lennon'``::
+
+ Blog.objects.filter(entry__headline__contains='Lennon')
+
Escaping parenthesis and underscores in LIKE statements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1106,37 +1130,41 @@ primary key field is called ``name``, these two statements are equivalent::
some_obj == other_obj
some_obj.name == other_obj.name
-OR lookups
-==========
+Complex lookups with Q objects
+==============================
-Keyword argument queries are "AND"ed together. If you have more
-complex query requirements (for example, you need to include an ``OR``
-statement in your query), you need to use ``Q`` objects.
+Keyword argument queries -- in ``filter()``, etc. -- are "AND"ed together. If
+you need to execute more more complex queries (for example, queries with ``OR``
+statements), you can use ``Q`` objects.
A ``Q`` object (``django.db.models.Q``) is an object used to encapsulate a
-collection of keyword arguments. These keyword arguments are specified in
-the same way as keyword arguments to the basic lookup functions like get()
-and filter(). For example::
+collection of keyword arguments. These keyword arguments are specified as in
+"Field lookups" above.
+
+For example, this ``Q`` object encapsulates a single ``LIKE`` query::
Q(question__startswith='What')
-is a ``Q`` object encapsulating a single ``LIKE`` query. ``Q`` objects can be
-combined using the ``&`` and ``|`` operators. When an operator is used on two
-``Q`` objects, it yields a new ``Q`` object. For example the statement::
+``Q`` objects can be combined using the ``&`` and ``|`` operators. When an
+operator is used on two ``Q`` objects, it yields a new ``Q`` object.
+
+For example, this statement yields a single ``Q`` object that represents the
+"OR" of two ``"question__startswith"`` queries::
Q(question__startswith='Who') | Q(question__startswith='What')
-... yields a single ``Q`` object that represents the "OR" of two
-"question__startswith" queries, equivalent to the SQL WHERE clause::
+This is equivalent to the following SQL ``WHERE`` clause::
- ... WHERE question LIKE 'Who%' OR question LIKE 'What%'
+ WHERE question LIKE 'Who%' OR question LIKE 'What%'
You can compose statements of arbitrary complexity by combining ``Q`` objects
-with the ``&`` and ``|`` operators. Parenthetical grouping can also be used.
+with the ``&`` and ``|`` operators. You can also use parenthetical grouping.
-One or more ``Q`` objects can then provided as arguments to the lookup
-functions. If multiple ``Q`` object arguments are provided to a lookup
-function, they will be "AND"ed together. For example::
+Each lookup function that takes keyword-arguments (e.g. ``filter()``,
+``exclude()``, ``get()``) can also be passed one or more ``Q`` objects as
+positional (not-named) arguments. If you provide multiple ``Q`` object
+arguments to a lookup function, the arguments will be "AND"ed together. For
+example::
Poll.objects.get(
Q(question__startswith='Who'),
@@ -1148,11 +1176,10 @@ function, they will be "AND"ed together. For example::
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
-If necessary, lookup functions can mix the use of ``Q`` objects and keyword
-arguments. All arguments provided to a lookup function (be they keyword
-argument or ``Q`` object) are "AND"ed together. However, if a ``Q`` object is
-provided, it must precede the definition of any keyword arguments. For
-example::
+Lookup functions can mix the use of ``Q`` objects and keyword arguments. All
+arguments provided to a lookup function (be they keyword arguments or ``Q``
+objects) are "AND"ed together. However, if a ``Q`` object is provided, it must
+precede the definition of any keyword arguments. For example::
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
@@ -1167,193 +1194,242 @@ example::
... would not be valid.
-A ``Q`` objects can also be provided to the ``complex`` keyword argument. For example::
-
- Poll.objects.get(
- complex=Q(question__startswith='Who') &
- (Q(pub_date=date(2005, 5, 2)) |
- Q(pub_date=date(2005, 5, 6))
- )
- )
-
See the `OR lookups examples page`_ for more examples.
.. _OR lookups examples page: http://www.djangoproject.com/documentation/models/or_lookups/
+Related objects
+===============
-Relationships (joins)
-=====================
+When you define a relationship in a model (i.e., a ``ForeignKey``,
+``OneToOneField``, or ``ManyToManyField``), instances of that model will have
+a convenient API to access the related object(s).
-When you define a relationship in a model (i.e., a ForeignKey,
-OneToOneField, or ManyToManyField), Django uses the name of the
-relationship to add a descriptor_ on every instance of the model.
-This descriptor behaves just like a normal attribute, providing
-access to the related object or objects. For example,
-``mychoice.poll`` will return the poll object associated with a specific
-instance of ``Choice``.
+Using the models at the top of this page, for example, an ``Entry`` object ``e``
+can get its associated ``Blog`` object by accessing the ``blog`` attribute:
+``e.blog``.
-.. _descriptor: http://users.rcn.com/python/download/Descriptor.htm
+(Behind the scenes, this functionality is implemented by Python descriptors_.
+This shouldn't really matter to you, but we point it out here for the curious.)
-Django also adds a descriptor for the 'other' side of the relationship -
+Django also creates API accessors for the "other" side of the relationship --
the link from the related model to the model that defines the relationship.
-Since the related model has no explicit reference to the source model,
-Django will automatically derive a name for this descriptor. The name that
-Django chooses depends on the type of relation that is represented. However,
-if the definition of the relation has a `related_name` parameter, Django
-will use this name in preference to deriving a name.
+For example, a ``Blog`` object ``b`` has access to a list of all related
+``Entry`` objects via the ``entry_set`` attribute: ``b.entry_set.all()``.
-There are two types of descriptor that can be employed: Single Object
-Descriptors and Object Set Descriptors. The following table describes
-when each descriptor type is employed. The local model is the model on
-which the relation is defined; the related model is the model referred
-to by the relation.
+All examples in this section use the sample ``Blog``, ``Author`` and ``Entry``
+models defined at the top of this page.
- =============== ============= =============
- Relation Type Local Model Related Model
- =============== ============= =============
- OneToOneField Single Object Single Object
+.. _descriptors: http://users.rcn.com/python/download/Descriptor.htm
- ForeignKey Single Object Object Set
+One-to-many relationships
+-------------------------
- ManyToManyField Object Set Object Set
- =============== ============= =============
+Forward
+~~~~~~~
-Single object descriptor
-------------------------
+If a model has a ``ForeignKey``, instances of that model will have access to
+the related (foreign) object via a simple attribute of the model.
+
+Example::
-If the related object is a single object, the descriptor acts
-just as if the related object were an attribute::
+ e = Entry.objects.get(id=2)
+ e.blog # Returns the related Blog object.
- # Obtain the existing poll
- old_poll = mychoice.poll
- # Set a new poll
- mychoice.poll = new_poll
- # Save the change
- mychoice.save()
+You can get and set via a foreign-key attribute. As you may expect, changes to
+the foreign key aren't saved to the database until you call ``save()``.
+Example::
-Whenever a change is made to a Single Object Descriptor, save()
-must be called to commit the change to the database.
+ e = Entry.objects.get(id=2)
+ e.blog = some_blog
+ e.save()
-If no `related_name` parameter is defined, Django will use the
-lower case version of the source model name as the name for the
-related descriptor. For example, if the ``Choice`` model had
-a field::
+If a ``ForeignKey`` field has ``null=True`` set (i.e., it allows ``NULL``
+values), you can assign ``None`` to it. Example::
- coordinator = models.OneToOneField(User)
+ e = Entry.objects.get(id=2)
+ e.blog = None
+ e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
-... instances of the model ``User`` would be able to call:
+Forward access to one-to-many relationships is cached the first time the
+related object is accessed. Subsequent accesses to the foreign key on the same
+object instance are cached. Example::
- old_choice = myuser.choice
- myuser.choice = new_choice
+ e = Entry.objects.get(id=2)
+ print e.blog # Hits the database to retrieve the associated Blog.
+ print e.blog # Doesn't hit the database; uses cached version.
-By default, relations do not allow values of None; if you attempt
-to assign None to a Single Object Descriptor, an AttributeError
-will be thrown. However, if the relation has 'null=True' set
-(i.e., the database will allow NULLs for the relation), None can
-be assigned and returned by the descriptor to represent empty
-relations.
+Note that the ``select_related()`` ``QuerySet`` method recursively prepopulates
+the cache of all one-to-many relationships ahead of time. Example::
-Access to Single Object Descriptors is cached. The first time
-a descriptor on an instance is accessed, the database will be
-queried, and the result stored. Subsequent attempts to access
-the descriptor on the same instance will use the cached value.
+ e = Entry.objects.select_related().get(id=2)
+ print e.blog # Doesn't hit the database; uses cached version.
+ print e.blog # Doesn't hit the database; uses cached version.
-Object set descriptor
----------------------
+``select_related()`` is documented in the "QuerySet methods that return new
+QuerySets" section above.
-An Object Set Descriptor acts just like the Manager - as an initial Query
-Set describing the set of objects related to an instance. As such, any
-query refining technique (filter, exclude, etc) can be used on the Object
-Set descriptor. This also means that Object Set Descriptor cannot be evaluated
-directly - the ``all()`` method must be used to produce a Query Set that
-can be evaluated.
+Backward
+~~~~~~~~
+
+If a model has a ``ForeignKey``, instances of the foreign-key model will have
+access to a ``Manager`` that returns all instances of the first model. By
+default, this ``Manager`` is named ``FOO_set``, where ``FOO`` is the source
+model name, lowercased. This ``Manager`` returns ``QuerySets``, which can be
+filtered and manipulated as described in the "Retrieving objects" section
+above.
-If no ``related_name`` parameter is defined, Django will use the lower case
-version of the source model name appended with `_set` as the name for the
-related descriptor. For example, every ``Poll`` object has a ``choice_set``
-descriptor.
+Example::
-The Object Set Descriptor has utility methods to add objects to the
-related object set:
+ b = Blog.objects.get(id=1)
+ b.entry_set.all() # Returns all Entry objects related to Blog.
-``add(obj1, obj2, ...)``
- Add the specified objects to the related object set.
+ # b.entry_set is a Manager that returns QuerySets.
+ b.entry_set.filter(headline__contains='Lennon')
+ b.entry_set.count()
-``create(\**kwargs)``
- Create a new object, and put it in the related object set. See
- _`Creating new objects`
+You can override the ``FOO_set`` name by setting the ``related_name``
+parameter in the ``ForeignKey()`` definition. For example, if the ``Entry``
+model was altered to ``blog = ForeignKey(Blog, related_name='entries')``, the
+above example code would look like this::
-The Object Set Descriptor may also have utility methods to remove objects
-from the related object set:
+ b = Blog.objects.get(id=1)
+ b.entries.all() # Returns all Entry objects related to Blog.
-``remove(obj1, obj2, ...)``
- Remove the specified objects from the related object set.
+ # b.entries is a Manager that returns QuerySets.
+ b.entries.filter(headline__contains='Lennon')
+ b.entries.count()
-``clear()``
- Remove all objects from the related object set.
+You cannot access a reverse ``ForeignKey`` ``Manager`` from the class; it must
+be accessed from an instance. Example::
-These two removal methods will not exist on ForeignKeys where ``Null=False``
-(such as in the Poll example). This is to prevent database inconsistency - if
-the related field cannot be set to None, then an object cannot be removed
-from one relation without adding it to another.
+ Blog.entry_set # Raises AttributeError: "Manager must be accessed via instance".
-The members of a related object set can be assigned from any iterable object.
-For example::
+In addition to the ``QuerySet`` methods defined in "Retrieving objects" above,
+the ``ForeignKey`` ``Manager`` has these additional methods:
- mypoll.choice_set = [choice1, choice2]
+ * ``add(obj1, obj2, ...)``: Adds the specified model objects to the related
+ object set.
-If the ``clear()`` method is available, any pre-existing objects will be removed
-from the Object Set before all objects in the iterable (in this case, a list)
-are added to the choice set. If the ``clear()`` method is not available, all
-objects in the iterable will be added without removing any existing elements.
+ Example::
-Each of these operations on the Object Set Descriptor has immediate effect
-on the database - every add, create and remove is immediately and
+ b = Blog.objects.get(id=1)
+ e = Entry.objects.get(id=234)
+ b.entry_set.add(e) # Associates Entry e with Blog b.
+
+ * ``create(**kwargs)``: Creates a new object, saves it and puts it in the
+ related object set. Returns the newly created object.
+
+ Example::
+
+ b = Blog.objects.get(id=1)
+ e = b.entry_set.create(headline='Hello', body_text='Hi', pub_date=datetime.date(2005, 1, 1))
+ # No need to call e.save() at this point -- it's already been saved.
+
+ This is equivalent to (but much simpler than)::
+
+ b = Blog.objects.get(id=1)
+ e = Entry(blog=b, headline='Hello', body_text='Hi', pub_date=datetime.date(2005, 1, 1))
+ e.save()
+
+ Note that there's no need to specify the keyword argument of the model
+ that defines the relationship. In the above example, we don't pass the
+ parameter ``blog`` to ``create()``. Django figures out that the new
+ ``Entry`` object's ``blog`` field should be set to ``b``.
+
+ * ``remove(obj1, obj2, ...)``: Removes the specified model objects from the
+ related object set.
+
+ Example::
+
+ b = Blog.objects.get(id=1)
+ e = Entry.objects.get(id=234)
+ b.entry_set.remove(e) # Disassociates Entry e from Blog b.
+
+ In order to prevent database inconsistency, this method only exists on
+ ``ForeignKey``s where ``null=True``. If the related field can't be set to
+ ``None`` (``NULL``), then an object can't be removed from a relation
+ without being added to another. In the above example, removing ``e`` from
+ ``b.entry_set()`` is equivalent to doing ``e.blog = None``, and because
+ the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this is invalid.
+
+ * ``clear()``: Removes all objects from the related object set.
+
+ Example::
+
+ b = Blog.objects.get(id=1)
+ b.entry_set.clear()
+
+ Note this doesn't delete the related objects -- it just disassociates
+ them.
+
+ Just like ``remove()``, ``clear()`` is only available on ``ForeignKey``s
+ where ``null=True``.
+
+To assign the members of a related set in one fell swoop, just assign to it
+from any iterable object. Example::
+
+ b = Blog.objects.get(id=1)
+ b.entry_set = [e1, e2]
+
+If the ``clear()`` method is available, any pre-existing objects will be
+removed from the ``entry_set`` before all objects in the iterable (in this
+case, a list) are added to the set. If the ``clear()`` method is *not*
+available, all objects in the iterable will be added without removing any
+existing elements.
+
+Each "reverse" operation described in this section has an immediate effect on
+the database. Every addition, creation and deletion is immediately and
automatically saved to the database.
-Relationships and queries
-=========================
+Many-to-many relationships
+--------------------------
-When composing a ``filter`` or ``exclude`` refinement, it may be necessary to
-include conditions that span relationships. Relations can be followed as deep
-as required - just add descriptor names, separated by double underscores, to
-describe the full path to the query attribute. The query::
+Both ends of a many-to-many relationship get automatic API access to the other
+end. The API works just as a "backward" one-to-many relationship. See _Backward
+above.
- Foo.objects.filter(name1__name2__name3__attribute__lookup=value)
+The only difference is in the attribute naming: The model that defines the
+``ManyToManyField`` uses the attribute name of that field itself, whereas the
+"reverse" model uses the lowercased model name of the original model, plus
+``'_set'`` (just like reverse one-to-many relationships).
-... is interpreted as 'get every Foo that has a name1 that has a name2 that
-has a name3 that has an attribute with lookup matching value'. In the Poll
-example::
+An example makes this easier to understand::
- Choice.objects.filter(poll__slug__startswith="eggs")
+ e = Entry.objects.get(id=3)
+ e.authors.all() # Returns all Author objects for this Entry.
+ e.authors.count()
+ e.authors.filter(name__contains='John')
-... describes the set of choices for which the related poll has a slug
-attribute that starts with "eggs". Django automatically composes the joins
-and conditions required for the SQL query.
+ a = Author.objects.get(id=5)
+ a.entry_set.all() # Returns all Entry objects for this Author.
-Creating new related objects
-============================
+Like ``ForeignKey``, ``ManyToManyField`` can specify ``related_name``. In the
+above example, if the ``ManyToManyField`` in ``Entry`` had specified
+``related_name='entries'``, then each ``Author`` instance would have an
+``entries`` attribute instead of ``entry_set``.
-Related objects are created using the ``create()`` convenience function on
-the descriptor Manager for relation::
+One-to-one relationships
+------------------------
- >>> p.choice_set.create(choice="Over easy", votes=0)
- >>> p.choice_set.create(choice="Scrambled", votes=0)
- >>> p.choice_set.create(choice="Fertilized", votes=0)
- >>> p.choice_set.create(choice="Poached", votes=0)
- >>> p.choice_set.count()
- 4
+The semantics of one-to-one relationships will be changing soon, so we don't
+recommend you use them.
-Each of those ``create()`` methods is equivalent to (but much simpler than)::
+How are the backward relationships possible?
+--------------------------------------------
- >>> c = Choice(poll_id=p.id, choice="Over easy", votes=0)
- >>> c.save()
+Other object-relational mappers require you to define relationships on both
+sides. The Django developers believe this is a violation of the DRY (Don't
+Repeat Yourself) principle, so Django only requires you to define the
+relationship on one end.
-Note that when using the `create()`` method, you do not give any value
-for the ``id`` field, nor do you give a value for the field that stores
-the relation (``poll_id`` in this case).
+But how is this possible, given that a model class doesn't know which other
+model classes are related to it until those other model classes are loaded?
-The ``create()`` method always returns the newly created object.
+The answer lies in the ``INSTALLED_APPS`` setting. The first time any model is
+loaded, Django iterates over every model in ``INSTALLED_APPS`` and creates the
+backward relationships in memory as needed. Essentially, one of the functions
+of ``INSTALLED_APPS`` is to tell Django the entire model domain.
Deleting objects
================
@@ -1361,23 +1437,23 @@ Deleting objects
The delete method, conveniently, is named ``delete()``. This method immediately
deletes the object and has no return value. Example::
- >>> c.delete()
-
-Objects can also be deleted in bulk. Every Query Set has a ``delete()`` method
-that will delete all members of the query set. For example::
+ e.delete()
- >>> Polls.objects.filter(pub_date__year=2005).delete()
+You can also delete objects in bulk. Every ``QuerySet`` has a ``delete()``
+method, which deletes all members of that ``QuerySet``.
-would bulk delete all Polls with a year of 2005. Note that ``delete()`` is the
-only Query Set method that is not exposed on the Manager itself.
+For example, this deletes all ``Entry`` objects with a ``pub_date`` year of
+2005::
-This is a safety mechanism to prevent you from accidentally requesting
-``Polls.objects.delete()``, and deleting *all* the polls.
+ Entry.objects.filter(pub_date__year=2005).delete()
-If you *actually* want to delete all the objects, then you have to explicitly
-request a complete query set::
+Note that ``delete()`` is the only ``QuerySet`` method that is not exposed on a
+``Manager`` itself. This is a safety mechanism to prevent you from accidentally
+requesting ``Entry.objects.delete()``, and deleting *all* the entries. If you
+*do* want to delete all the objects, then you have to explicitly request a
+complete query set::
- Polls.objects.all().delete()
+ Entry.objects.all().delete()
Extra instance methods
======================
@@ -1397,9 +1473,9 @@ following model::
('M', 'Male'),
('F', 'Female'),
)
- class Person
- name = meta.CharField(maxlength=20)
- gender = meta.CharField(maxlength=1, choices=GENDER_CHOICES)
+ class Person(models.Model):
+ name = models.CharField(maxlength=20)
+ gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
...each ``Person`` instance will have a ``get_gender_display()`` method. Example::
Please sign in to comment.
Something went wrong with that request. Please try again.