summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-04-27 02:50:16 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-04-27 02:50:16 +0000
commit9c52d56f6f8a9cdafb231adf9f4110473099c9b5 (patch)
treeeeded174bec983e4415f5f52f187b3d5d9a1882d /docs
parentc91a30f00fd182faf8ca5c03cd7dbcf8b735b458 (diff)
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing code. Also adds a couple of new features. Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658 git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs')
-rw-r--r--docs/db-api.txt436
-rw-r--r--docs/model-api.txt276
2 files changed, 642 insertions, 70 deletions
diff --git a/docs/db-api.txt b/docs/db-api.txt
index f8ed16988e..6a3fe88080 100644
--- a/docs/db-api.txt
+++ b/docs/db-api.txt
@@ -160,37 +160,6 @@ When you save an object, Django performs the following steps:
is used to provide notification that an object has been successfully
saved. (These signals are not yet documented.)
-Raw saves
-~~~~~~~~~
-
-**New in Django development version**
-
-The pre-processing step (#2 in the previous section) is useful, but it modifies
-the data stored in a field. This can cause problems if you're relying upon the
-data you provide being used as-is.
-
-For example, if you're setting up conditions for a test, you'll want the test
-conditions to be repeatable. If pre-processing is performed, the data used
-to specify test conditions may be modified, changing the conditions for the
-test each time the test is run.
-
-In cases such as this, you need to prevent pre-processing from being performed
-when you save an object. To do this, you can invoke a **raw save** by passing
-``raw=True`` as an argument to the ``save()`` method::
-
- b4.save(raw=True) # Save object, but do no pre-processing
-
-A raw save skips the usual data pre-processing that is performed during the
-save. All other steps in the save (pre-save signal, data preparation, data
-insertion, and post-save signal) are performed as normal.
-
-.. admonition:: When to use a raw save
-
- Generally speaking, you shouldn't need to use a raw save. Disabling field
- pre-processing is an extraordinary measure that should only be required
- in extraordinary circumstances, such as setting up reliable test
- conditions.
-
Saving changes to objects
=========================
@@ -211,11 +180,11 @@ Saving ForeignKey and ManyToManyField fields
--------------------------------------------
Updating ``ForeignKey`` fields works exactly the same way as saving a normal
-field; simply assign an object of the right type to the field in question::
+field; simply assign an object of the right type to the field in question::
- cheese_blog = Blog.objects.get(name="Cheddar Talk")
- entry.blog = cheese_blog
- entry.save()
+ cheese_blog = Blog.objects.get(name="Cheddar Talk")
+ entry.blog = cheese_blog
+ entry.save()
Updating a ``ManyToManyField`` works a little differently; use the ``add()``
method on the field to add a record to the relation::
@@ -422,6 +391,14 @@ This returns the sixth through tenth objects (``OFFSET 5 LIMIT 5``)::
Entry.objects.all()[5:10]
+You can also slice from the item ''N'' to the end of the queryset. For
+example, to return everything from the fixth item onwards::
+
+ Entry.objects.all()[5:]
+
+How this last example is implemented in SQL varies depending upon the database
+used, but it is supported in all cases.
+
Generally, slicing a ``QuerySet`` returns a new ``QuerySet`` -- it doesn't
evaluate the query. An exception is if you use the "step" parameter of Python
slice syntax. For example, this would actually execute the query in order to
@@ -514,15 +491,70 @@ like so::
Note: ``order_by('?')`` queries may be expensive and slow, depending on the
database backend you're using.
-To order by a field in a different table, add the other table's name and a dot,
-like so::
+To order by a field in a different model, use the same syntax as when you are
+querying across model relations. That is, the name of the field, followed by a
+double underscore (``__``), followed by the name of the field in the new model,
+and so on for as many models as you want to join. For example::
+
+ Entry.objects.order_by('blog__name', 'headline')
+
+If you try to order by a field that is a relation to another model, Django will
+use the default ordering on the related model (or order by the related model's
+primary key if there is no ``Meta.ordering`` specified. For example::
+
+ Entry.objects.order_by('blog')
+
+...is identical to::
+
+ Entry.objects.order_by('blog__id')
+
+...since the ``Blog`` model has no default ordering specified.
- Entry.objects.order_by('blogs_blog.name', 'headline')
+Be cautious when ordering by fields in related models if you are also using
+``distinct()``. See the note in the `distinct()`_ section for an explanation
+of how related model ordering can change the expected results.
+
+It is permissible to specify a multi-valued field to order the results by (for
+example, a ``ManyToMany`` field). Normally this won't be a sensible thing to
+do and it's really an advanced usage feature. However, if you know that your
+queryset's filtering or available data implies that there will only be one
+ordering piece of data for each of the main items you are selecting, the
+ordering may well be exactly what you want to do. Use ordering on multi-valued
+fields with care and make sure the results are what you expect.
+
+**New in Django development version:** If you don't want any ordering to be
+applied to a query, not even the default ordering, call ``order_by()`` with no
+parameters.
+
+**New in Django development version:** The syntax for ordering across related
+models has changed. See the `Django 0.96 documentation`_ for the old behaviour.
+
+.. _Django 0.96 documentation: http://www.djangoproject.com/documentation/0.96/model-api/#floatfield
There's no way to specify whether ordering should be case sensitive. With
respect to case-sensitivity, Django will order results however your database
backend normally orders them.
+``reverse()``
+~~~~~~~~~~~~~
+
+**New in Django development version**
+
+If you want to reverse the order in which a queryset's elements are returned,
+you can use the ``reverse()`` method. Calling ``reverse()`` a second time
+restores the ordering back to the normal direction.
+
+To retrieve the ''last'' five items in a queryset, you could do this::
+
+ my_queryset.reverse()[:5]
+
+Note that this is not quite the same as slicing from the end of a sequence in
+Python. The above example will return the last item first, then the
+penultimate item and so on. If we had a Python sequence and looked at
+``seq[:-5]``, we would see the fifth-last item first. Django doesn't support
+that mode of access (slicing from the end), since it is not possible to do it
+efficiently in SQL.
+
``distinct()``
~~~~~~~~~~~~~~
@@ -531,10 +563,28 @@ eliminates duplicate rows from the query results.
By default, a ``QuerySet`` will not eliminate duplicate rows. In practice, this
is rarely a problem, because simple queries such as ``Blog.objects.all()``
-don't introduce the possibility of duplicate result rows.
+don't introduce the possibility of duplicate result rows. However, if your
+query spans multiple tables, it's possible to get duplicate results when a
+``QuerySet`` is evaluated. That's when you'd use ``distinct()``.
+
+.. note::
+ Any fields used in an ``order_by()`` call are included in the SQL
+ ``SELECT`` columns. This can sometimes lead to unexpected results when
+ used in conjuntion with ``distinct()``. If you order by fields from a
+ related model, those fields will be added to the selected columns and they
+ may make otherwise duplicate rows appear to be distinct. Since the extra
+ columns don't appear in the returned results (they are only there to
+ support ordering), it sometimes looks like non-distinct results are being
+ returned.
+
+ Similarly, if you use a ``values()`` query to restrict the columns
+ selected, the columns used in any ``order_by()`` (or default model
+ ordering) will still be involved and may affect uniqueness of the results.
-However, if your query spans multiple tables, it's possible to get duplicate
-results when a ``QuerySet`` is evaluated. That's when you'd use ``distinct()``.
+ The moral here is that if you are using ``distinct()`` be careful about
+ ordering by related models. Similarly, when using ``distinct()`` and
+ ``values()`` together, be careful when ordering by fields not in the
+ ``values()`` call.
``values(*fields)``
~~~~~~~~~~~~~~~~~~~
@@ -569,6 +619,43 @@ Example::
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]
+You can also retrieve values from across ``ForeignKey`` relations by using
+double underscores to separate the field names, just as when calling the
+``filter()`` command. For example::
+
+ >>> Entry.objects.values('blog__name').distinct()
+ [{'name': 'Beatles Blog'}]
+
+A couple of subtleties that are worth mentioning:
+
+ * The ``values()`` method does not return anything for ``ManyToManyField``
+ attributes and will raise an error if you try to pass in this type of
+ field to it.
+ * If you have a field called ``foo`` that is a ``ForeignKey``, the default
+ ``values()`` call will return a dictionary key called ``foo_id``, since
+ this is the name of the hidden model attribute that stores the actual
+ value (the ``foo`` attribute refers to the related model). When you are
+ calling ``values()`` and passing in field names, you can pass in either
+ ``foo`` or ``foo_id`` and you will get back the same thing (the
+ dictionary key will match the field name you passed in).
+
+ For example::
+
+ >>> Entry.objects.values()
+ [{'blog_id: 1, 'headline': u'First Entry', ...}, ...]
+
+ >>> Entry.objects.values('blog')
+ [{'blog': 1}, ...]
+
+ >>> Entry.objects.values('blog_id')
+ [{'blog_id': 1}, ...]
+ * When using ``values()`` together with ``distinct()``, be aware that
+ ordering can affect the results. See the note in the `distinct()`_
+ section, above, for details.
+
+**New in Django development version:** Previously, it was not possible to pass
+``blog_id`` to ``values()`` in the above example, only ``blog``.
+
A ``ValuesQuerySet`` is useful when you know you're only going to need values
from a small number of the available fields and you won't need the
functionality of a model instance object. It's more efficient to select only
@@ -586,6 +673,34 @@ followed (optionally) by any output-affecting methods (such as ``values()``),
but it doesn't really matter. This is your chance to really flaunt your
individualism.
+``values_list(*fields)``
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+This is similar to ``values()`` except that instead of returning a list of
+dictionaries, it returns a list of tuples. Each tuple contains the value from
+the respective field passed into the ``values_list()`` call -- so the first
+item is the first field, etc. For example::
+
+ >>> Entry.objects.values_list('id', 'headling')
+ [(1, u'First entry'), ...]
+
+If you only pass in a single field, you can also pass in the ``flat``
+parameter. If ``True``, this will mean the returned results are single values,
+rather than one-tuples. An example should make the difference clearer::
+
+ >>> Entry.objects.values_list('id').order_by('id')
+ [(1,), (2,), (3,), ...]
+
+ >>> Entry.objects.values_list('id', flat=True).order_by('id')
+ [1, 2, 3, ...]
+
+It is an error to pass in ``flat`` when there is more than one field.
+
+If you don't pass any values to ``values_list()``, it will return all the
+fields in the model, in the order they were declared.
+
``dates(field, kind, order='ASC')``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -635,6 +750,17 @@ Examples::
>>> Entry.objects.none()
[]
+``all()``
+~~~~~~~~~~
+
+**New in Django development version**
+
+Returns a ''copy'' of the current ``QuerySet`` (or ``QuerySet`` subclass you
+pass in). This can be useful in some situations where you might want to pass
+in either a model manager or a ``QuerySet`` and do further filtering on the
+result. You can safely call ``all()`` on either object and then you'll
+definitely have a ``QuerySet`` to work with.
+
``select_related()``
~~~~~~~~~~~~~~~~~~~~
@@ -687,8 +813,8 @@ related ``Person`` *and* the related ``City``::
p = b.author # Hits the database.
c = p.hometown # Hits the database.
-Note that ``select_related()`` does not follow foreign keys that have
-``null=True``.
+Note that, by default, ``select_related()`` does not follow foreign keys that
+have ``null=True``.
Usually, using ``select_related()`` can vastly improve performance because your
app can avoid many database calls. However, in situations with deeply nested
@@ -705,8 +831,43 @@ follow::
The ``depth`` argument is new in the Django development version.
-``extra(select=None, where=None, params=None, tables=None)``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+**New in Django development version:** Sometimes you only need to access
+specific models that are related to your root model, not all of the related
+models. In these cases, you can pass the related field names to
+``select_related()`` and it will only follow those relations. You can even do
+this for models that are more than one relation away by separating the field
+names with double underscores, just as for filters. For example, if we have
+thise model::
+
+ class Room(models.Model):
+ # ...
+ building = models.ForeignKey(...)
+
+ class Group(models.Model):
+ # ...
+ teacher = models.ForeignKey(...)
+ room = models.ForeignKey(Room)
+ subject = models.ForeignKey(...)
+
+...and we only needed to work with the ``room`` and ``subject`` attributes, we
+could write this::
+
+ g = Group.objects.select_related('room', 'subject')
+
+This is also valid::
+
+ g = Group.objects.select_related('room__building', 'subject')
+
+...and would also pull in the ``building`` relation.
+
+You can only refer to ``ForeignKey`` relations in the list of fields passed to
+``select_related``. You *can* refer to foreign keys that have ``null=True``
+(unlike the default ``select_related()`` call). It's an error to use both a
+list of fields and the ``depth`` parameter in the same ``select_related()``
+call, since they are conflicting options.
+
+``extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes, the Django query syntax by itself can't easily express a complex
``WHERE`` clause. For these edge cases, Django provides the ``extra()``
@@ -763,6 +924,21 @@ of the arguments is required, but you should use at least one of them.
some database backends, such as some MySQL versions, don't support
subqueries.
+ **New in Django development version**
+ In some rare cases, you might wish to pass parameters to the SQL fragments
+ in ``extra(select=...)```. For this purpose, use the ``select_params``
+ parameter. Since ``select_params`` is a sequence and the ``select``
+ attribute is a dictionary, some care is required so that the parameters
+ are matched up correctly with the extra select pieces. In this situation,
+ you should use a ``django.utils.datastructures.SortedDict`` for the
+ ``select`` value, not just a normal Python dictionary.
+
+ This will work, for example::
+
+ Blog.objects.extra(
+ select=SortedDict(('a', '%s'), ('b', '%s')),
+ select_params=('one', 'two'))
+
``where`` / ``tables``
You can define explicit SQL ``WHERE`` clauses -- perhaps to perform
non-explicit joins -- by using ``where``. You can manually add tables to
@@ -779,20 +955,61 @@ of the arguments is required, but you should use at least one of them.
SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);
+ Be careful when using the ``tables`` parameter if you're specifying
+ tables that are already used in the query. When you add extra tables
+ via the ``tables`` parameter, Django assumes you want that table included
+ an extra time, if it is already included. That creates a problem,
+ since the table name will then be given an alias. If a table appears
+ multiple times in an SQL statement, the second and subsequent occurrences
+ must use aliases so the database can tell them apart. If you're
+ referring to the extra table you added in the extra ``where`` parameter
+ this is going to cause errors.
+
+ Normally you'll only be adding extra tables that don't already appear in
+ the query. However, if the case outlined above does occur, there are a few
+ solutions. First, see if you can get by without including the extra table
+ and use the one already in the query. If that isn't possible, put your
+ ``extra()`` call at the front of the queryset construction so that your
+ table is the first use of that table. Finally, if all else fails, look at
+ the query produced and rewrite your ``where`` addition to use the alias
+ given to your extra table. The alias will be the same each time you
+ construct the queryset in the same way, so you can rely upon the alias
+ name to not change.
+
+``order_by``
+ If you need to order the resulting queryset using some of the new fields
+ or tables you have included via ``extra()`` use the ``order_by`` parameter
+ to ``extra()`` and pass in a sequence of strings. These strings should
+ either be model fields (as in the normal ``order_by()`` method on
+ querysets), of the form ``table_name.column_name`` or an alias for a column
+ that you specified in the ``select`` parameter to ``extra()``.
+
+ For example::
+
+ q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
+ q = q.extra(order_by = ['-is_recent'])
+
+ This would sort all the items for which ``is_recent`` is true to the front
+ of the result set (``True`` sorts before ``False`` in a descending
+ ordering).
+
+ This shows, by the way, that you can make multiple calls to
+ ``extra()`` and it will behave as you expect (adding new constraints each
+ time).
+
``params``
- The ``select`` and ``where`` parameters described above may use standard
- Python database string placeholders -- ``'%s'`` to indicate parameters the
- database engine should automatically quote. The ``params`` argument is a
- list of any extra parameters to be substituted.
+ The ``where`` parameter described above may use standard Python database
+ string placeholders -- ``'%s'`` to indicate parameters the database engine
+ should automatically quote. The ``params`` argument is a list of any extra
+ parameters to be substituted.
Example::
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
- Always use ``params`` instead of embedding values directly into ``select``
- or ``where`` because ``params`` will ensure values are quoted correctly
- according to your particular backend. (For example, quotes will be escaped
- correctly.)
+ Always use ``params`` instead of embedding values directly into ``where``
+ because ``params`` will ensure values are quoted correctly according to
+ your particular backend. (For example, quotes will be escaped correctly.)
Bad::
@@ -802,8 +1019,9 @@ of the arguments is required, but you should use at least one of them.
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
- The combined number of placeholders in the list of strings for ``select``
- or ``where`` should equal the number of values in the ``params`` list.
+**New in Django development version** The ``select_params`` argument to
+``extra()`` is new. Previously, you could attempt to pass parameters for
+``select`` in the ``params`` argument, but it worked very unreliably.
QuerySet methods that do not return QuerySets
---------------------------------------------
@@ -1031,7 +1249,12 @@ Examples::
SQL equivalents::
SELECT ... WHERE id = 14;
- SELECT ... WHERE id = NULL;
+ SELECT ... WHERE id IS NULL;
+
+**New in Django development version:** The semantics of ``id__exact=None`` have
+changed in the development version. Previously, it was (intentionally)
+converted to ``WHERE id = NULL`` at the SQL level, which would never match
+anything. It has now been changed to behave the same as ``id__isnull=True``.
iexact
~~~~~~
@@ -1261,14 +1484,6 @@ SQL equivalent::
SELECT ... WHERE pub_date IS NULL;
-.. admonition:: ``__isnull=True`` vs ``__exact=None``
-
- There is an important difference between ``__isnull=True`` and
- ``__exact=None``. ``__exact=None`` will *always* return an empty result
- set, because SQL requires that no value is equal to ``NULL``.
- ``__isnull`` determines if the field is currently holding the value
- of ``NULL`` without performing a comparison.
-
search
~~~~~~
@@ -1368,6 +1583,11 @@ equivalent::
Entry.objects.filter(blog__id=3) # __exact is implied
Entry.objects.filter(blog__pk=3) # __pk implies __id__exact
+.. note::
+ Because of this shortcut, you cannot have a field called ``pk`` that is not
+ the primary key of the model. It will always be replaced by the name of the
+ model's primary key in queries.
+
Lookups that span relationships
-------------------------------
@@ -1392,6 +1612,60 @@ whose ``headline`` contains ``'Lennon'``::
Blog.objects.filter(entry__headline__contains='Lennon')
+Spanning multi-valued relationships
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+When you are filtering an object based on a ``ManyToManyField`` or a reverse
+``ForeignKeyField``, there are two different sorts of filter you may be
+interested in. Consider the ``Blog``/``Entry`` relationship (``Blog`` to
+``Entry`` is a one-to-many relation). We might be interested in finding blogs
+that have an entry which has both *"Lennon"* in the headline and was published
+today. Or we might want to find blogs that have an entry with *"Lennon"* in
+the headline as well as an entry that was published today. Since there are
+multiple entries associated with a single ``Blog``, both of these queries are
+possible and make sense in some situations.
+
+The same type of situation arises with a ``ManyToManyField``. For example, if
+an ``Entry`` has a ``ManyToManyField`` called ``tags``, we might want to find
+entries linked to tags called *"music"* and *"bands"* or we might want an
+entry that contains a tag with a name of *"music"* and a status of *"public"*.
+
+To handle both of these situations, Django has a consistent way of processing
+``filter()`` and ``exclude()`` calls. Everything inside a single ``filter()``
+call is applied simultaneously to filter out items matching all those
+requirements. Successive ``filter()`` calls further restrict the set of
+objects, but for multi-valued relations, they apply to any object linked to
+the primary model, not necessarily those objects that were selected by an
+earlier ``filter()`` call.
+
+That may sound a bit confusing, so hopefully an example will clarify. To
+select all blogs that contains entries with *"Lennon"* in the headline and
+were published today, we would write::
+
+ Blog.objects.filter(entry__headline__contains='Lennon',
+ entry__pub_date=datetime.date.today())
+
+To select all blogs that contain an entry with *"Lennon"* in the headline
+**as well as** an entry that was published today, we would write::
+
+ Blog.objects.filter(entry__headline__contains='Lennon').filter(
+ entry__pub_date=datetime.date.today())
+
+In this second example, the first filter restricted the queryset to all those
+blogs linked to that particular type of entry. The second filter restricted
+the set of blogs *further* to those that are also linked to the second type of
+entry. The entries select by the second filter may or may not be the same as
+the entries in the first filter. We are filtering the ``Blog`` items with each
+filter statement, not the ``Entry`` items.
+
+All of this behaviour also applies to ``exclude()``: all the conditions in a
+single ``exclude()`` statement apply to a single instance (if those conditions
+are talking about the same multi-valued relation). Conditions in subsequent
+``filter()`` or ``exclude()`` calls that refer to the same relation may end up
+filtering on different linked objects.
+
Escaping percent signs and underscores in LIKE statements
---------------------------------------------------------
@@ -1496,6 +1770,12 @@ This is equivalent to the following SQL ``WHERE`` clause::
You can compose statements of arbitrary complexity by combining ``Q`` objects
with the ``&`` and ``|`` operators. You can also use parenthetical grouping.
+**New in Django development version:** ``Q`` objects can also be negated using
+the ``~`` operator, allowing for combined lookups that combine both a normal
+query and a negated (``NOT``) query::
+
+ Q(question__startswith='Who') | ~Q(pub_date__year=2005)
+
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
@@ -1815,6 +2095,34 @@ complete query set::
Entry.objects.all().delete()
+Updating multiple objects at once
+=================================
+
+**New in Django development version**
+
+Sometimes you want to set a field to a particular value for all the objects in
+a queryset. You can do this with the ``update()`` method. For example::
+
+ # Update all the headlings to the same value.
+ Entry.objects.all().update(headline='Everything is the same')
+
+You can only set non-relation fields and ``ForeignKey`` fields using this
+method and the value you set the field to must be a normal Python value (you
+can't set a field to be equal to some other field at the moment).
+
+To update ``ForeignKey`` fields, set the new value to be the new model
+instance you want to point to. Example::
+
+ b = Blog.objects.get(pk=1)
+ # Make all entries belong to this blog.
+ Entry.objects.all().update(blog=b)
+
+The ``update()`` method is applied instantly and doesn't return anything
+(similar to ``delete()``). The only restriction on the queryset that is
+updated is that it can only access one database table, the model's main
+table. So don't try to filter based on related fields or anything like that;
+it won't work.
+
Extra instance methods
======================
diff --git a/docs/model-api.txt b/docs/model-api.txt
index f73c5aadf7..a5a2e2932e 100644
--- a/docs/model-api.txt
+++ b/docs/model-api.txt
@@ -886,6 +886,10 @@ relationship should work. All are optional:
`related objects documentation`_ for a full
explanation and example.
+ If using this in an `abstract base class`_, be
+ sure to read the `extra notes`_ in that section
+ about ``related_name``.
+
``to_field`` The field on the related object that the relation
is to. By default, Django uses the primary key of
the related object.
@@ -893,6 +897,8 @@ relationship should work. All are optional:
.. _`Database API reference`: ../db-api/
.. _related objects documentation: ../db-api/#related-objects
+.. _abstract base class: `Abstract base classes`_
+.. _extra notes: `Be careful with related_name`_
Many-to-many relationships
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -988,9 +994,6 @@ the relationship should work. All are optional:
One-to-one relationships
~~~~~~~~~~~~~~~~~~~~~~~~
-The semantics of one-to-one relationships will be changing soon, so we don't
-recommend you use them. If that doesn't scare you away, keep reading.
-
To define a one-to-one relationship, use ``OneToOneField``. You use it just
like any other ``Field`` type: by including it as a class attribute of your
model.
@@ -1012,9 +1015,26 @@ As with ``ForeignKey``, a relationship to self can be defined by using the
string ``"self"`` instead of the model name; references to as-yet undefined
models can be made by using a string containing the model name.
-This ``OneToOneField`` will actually replace the primary key ``id`` field
-(since one-to-one relations share the same primary key), and will be displayed
-as a read-only field when you edit an object in the admin interface:
+Finally, ``OneToOneField`` takes the following extra option:
+
+ ======================= ============================================================
+ Argument Description
+ ======================= ============================================================
+ ``parent_link`` When ``True`` and used in a model inherited from
+ another model, indicates that this field should
+ be used as the link from the child back to the
+ parent. See `Model inheritance`_ for more
+ details.
+
+ **New in Django development version**
+
+ ======================= ============================================================
+
+**New in Django development version:** ``OneToOneField`` classes used to
+automatically become the primary key on a model. This is no longer true,
+although you can manually pass in the ``primary_key`` attribute if you like.
+Thus, it's now possible to have multiple fields of type ``OneToOneField`` on a
+single model.
See the `One-to-one relationship model example`_ for a full example.
@@ -1048,6 +1068,14 @@ Model metadata is "anything that's not a field", such as ordering options, etc.
Here's a list of all possible ``Meta`` options. No options are required. Adding
``class Meta`` to a model is completely optional.
+``abstract``
+------------
+
+**New in Django development version**
+
+When set to ``True``, denotes this model as an abstract base class. See
+`Abstract base classes`_ for more details. Defaults to ``False``.
+
``db_table``
------------
@@ -1155,6 +1183,10 @@ together. It's used in the Django admin and is enforced at the database
level (i.e., the appropriate ``UNIQUE`` statements are included in the
``CREATE TABLE`` statement).
+All the fields specified in ``unique_together`` must be part of the current
+model. If you are using `model inheritance`_, you cannot refer to fields from
+any parent classes in ``unique_together``.
+
**New in Django development version**
For convenience, unique_together can be a single list when dealing
@@ -2041,6 +2073,238 @@ You can also prevent saving::
.. _database API docs: ../db-api/
+Model inheritance
+=================
+
+**New in Django development version**
+
+Model inheritance in Django works almost identically to the way normal class
+inheritance works in Python. The only decision you have to make is whether you
+want the parent models to be models in their own right (with their own
+database tables), or if the parents are just holders of common information
+that will only be visible through the child models.
+
+Often, you will just want to use the parent class to hold information that you
+don't want to have to type out for each child model. This class isn't going to
+ever be used in isolation, so `abstract base classes`_ are what you're after. However, if you're subclassing an existing model (perhaps something from another application entirely), or want each model to have its own database table, `multi-table inheritance`_ is the way to go.
+
+Abstract base classes
+---------------------
+
+Abstract base classes are useful when you want to put some common information
+into a number of other models. You write your base class and put
+``abstract=True`` in the ``Meta`` class. This model will then not be used to
+create any database table. Instead, when it is used as a base class for other
+models, its fields will be added to those of the child class. It is an error
+to have fields in the abstract base class with the same name as those in the
+child (and Django will raise an exception).
+
+An example::
+
+ class CommonInfo(models.Model):
+ name = models.CharField(max_length=100)
+ age = models.PositiveIntegerField()
+
+ class Meta:
+ abstract = True
+
+ class Student(CommonInfo):
+ home_group = models.CharField(max_length=5)
+
+The ``Student`` model will have three fields: ``name``, ``age`` and
+``home_group``. The ``CommonInfo`` model cannot be used as a normal Django
+model, since it is an abstract base class. It does not generate a database
+table or have a manager or anything like that.
+
+For many uses, this type of model inheritance will be exactly what you want.
+It provides a way to factor out common information at the Python level, whilst
+still only creating one database table per child model at the database level.
+
+``Meta`` inheritance
+~~~~~~~~~~~~~~~~~~~~
+
+When an abstract base class is created, Django makes any ``Meta`` inner class
+you declared on the base class available as an attribute. If a child class
+does not declared its own ``Meta`` class, it will inherit the parent's
+``Meta``. If the child wants to extend the parent's ``Meta`` class, it can
+subclass it. For example::
+
+ class CommonInfo(models.Model):
+ ...
+ class Meta:
+ abstract = True
+ ordering = ['name']
+
+ class Student(CommonInfo):
+ ...
+ class Meta(CommonInfo.Meta):
+ db_table = 'student_info'
+
+Django does make one adjustment to the ``Meta`` class of an abstract base
+class: before installing the ``Meta`` attribute, it sets ``abstract=False``.
+This means that children of abstract base classes don't automatically become
+abstract classes themselves. Of course, you can make an abstract base class
+that inherits from another abstract base class. You just need to remember to
+explicitly set ``abstract=True`` each time.
+
+Some attributes won't make sense to include in the ``Meta`` class of an
+abstract base class. For example, including ``db_table`` would mean that all
+the child classes (the ones that don't specify their own ``Meta``) would use
+the same database table, which is almost certainly not what you want.
+
+Be careful with ``related_name``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are using the ``related_name`` attribute on a ``ForeignKey`` or
+``ManyToManyField``, you must always specify a *unique* reverse name for the
+field. This would normally cause a problem in abstract base classes, since the
+fields on this class are included into each of the child classes, with exactly
+the same values for the attributes (including ``related_name``) each time.
+
+To work around this problem, when you are using ``related_name`` in an
+abstract base class (only), part of the name should be the string
+``'%(class)s'``. This is replaced by the lower-cased name of the child class
+that the field is used in. Since each class has a different name, each related
+name will end up being different. For example::
+
+ class Base(models.Model):
+ m2m = models.ManyToMany(OtherModel, related_name="%(class)s_related")
+
+ class Meta:
+ abstract = True
+
+ class ChildA(Base):
+ pass
+
+ class ChildB(Base):
+ pass
+
+The reverse name of the ``ChildA.m2m`` field will be ``childa_related``,
+whilst the reverse name of the ``ChildB.m2m`` field will be
+``childb_related``. It is up to you how you use the ``'%(class)s'`` portion to
+construct your related name, but if you forget to use it, Django will raise
+errors when you validate your models (or run ``syncdb``).
+
+If you don't specify a ``related_name`` attribute for a field in an abstract
+base class, the default reverse name will be the name of the child class
+followed by ``'_set'``, just as it normally would be if you'd declared the field directly on the child class. For example, in the above code, if the ``related_name`` attribute was omitted, the reverse name for the ``m2m`` field would be ``childa_set`` in the ``ChildA`` case and ``childb_set`` for the ``ChildB`` field.
+
+Multi-table inheritance
+-----------------------
+
+The second type of model inheritance supported by Django is when each model in
+the hierarchy is a model all by itself. Each model corresponds to its own
+database table and can be queried and created indvidually. The inheritance
+relationship introduces links between the child model and each of its parents
+(via an automatically created ``OneToOneField``). For example::
+
+ class Place(models.Model):
+ name = models.CharField(max_length=50)
+ address = models.CharField(max_length=80)
+
+ class Restaurant(Place):
+ serves_hot_dogs = models.BooleanField()
+ serves_pizza = models.BooleanField()
+
+All of the fields of ``Place`` will also be available in ``Restaurant``,
+although the data will reside in a different database table. So these are both
+possible::
+
+ >>> Place.objects.filter(name="Bob's Cafe")
+ >>> Restaurant.objects.filter(name="Bob's Cafe")
+
+If you have a ``Place`` that is also a ``Restaurant``, you can get from the
+``Place`` object to the ``Restaurant`` object by using the lower-case version
+of the model name::
+
+ >>> p = Place.objects.filter(name="Bob's Cafe")
+ # If Bob's Cafe is a Restaurant object, this will give the child class:
+ >>> p.restaurant
+ <Restaurant: ...>
+
+However, if ``p`` in the above example was *not* a ``Restaurant`` (it had been
+created directly as a ``Place`` object or was the parent of some other class),
+referring to ``p.restaurant`` would give an error.
+
+``Meta`` and multi-table inheritance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In the multi-table inheritance situation, it doesn't make sense for a child
+class to inherit from its parent's ``Meta`` class. All the ``Meta`` options
+have already been applied to the parent class and applying them again would
+normally only lead to contradictory behaviour (this is in contrast with the
+abstract base class case, where the base class doesn't exist in its own
+right).
+
+So a child model does not have access to its parent's ``Meta`` class. However,
+there are a few limited cases where the child inherits behaviour from the
+parent: if the child does not specify an ``ordering`` attribute or a
+``get_latest_by`` attribute, it will inherit these from its parent.
+
+If the parent has an ordering and you don't want the child to have any natural
+ordering, you can explicity set it to be empty::
+
+ class ChildModel(ParentModel):
+ ...
+ class Meta:
+ # Remove parent's ordering effect
+ ordering = []
+
+Inheritance and reverse relations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Because multi-table inheritance uses an implicit ``OneToOneField`` to link the
+child and the parent, it's possible to move from the parent down to the child,
+as in the above example. However, this uses up the name that is the default
+``related_name`` value for ``ForeignKey`` and ``ManyToManyField`` relations.
+If you are putting those type of relations on a subclass of another model, you
+**must** specify the ``related_name`` attribute on each such field. If you
+forget, Django will raise an error when you run ``manage.py validate`` or try
+to syncdb.
+
+For example, using the above ``Place`` class again, let's create another
+subclass with a ``ManyToManyField``::
+
+ class Supplier(Place):
+ # Must specify related_name on all relations.
+ customers = models.ManyToManyField(Restaurant,
+ related_name='provider')
+
+For more information about reverse relations, refer to the `Database API
+reference`_ . For now, just remember to run ``manage.py validate`` when
+you're writing your models and pay attention to the error messages.
+
+Specifying the parent link field
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As mentioned, Django will automatically create a ``OneToOneField`` linking
+your child class back any non-abstract parent models. If you want to control
+the name of the attribute linking back to the parent, you can create your own
+link field and pass it ``parent_link=True``. For example, to explicitly
+specify the field that will link ``Supplier`` to ``Place`` in the above
+example, you could write::
+
+ class Supplier(Place):
+ parent = models.OneToOneField(Place, parent_link=True)
+ ...
+
+Multiple inheritance
+--------------------
+
+Just as with Python's subclassing, it's possible for a Django model to inherit
+from multiple parent models. Keep in mind that normal Python name resolution
+rules apply. The first base class that a particular name appears in (e.g.
+``Meta``) will be the one that is used. We stop searching once we find the
+name once. This means that if multiple parents contain a ``Meta`` class, only
+the first one is going to be used. All others will be ignored.
+
+Generally, you won't need to inherit from multiple parents. The main use-case
+where this is useful is for ''mix-in'' classes: adding a particular extra
+field or method to every class that inherits the mix-in. Try to keep your
+inheritance hierarchies as simple and straightforward as possible so that you
+won't have to struggle to work out where a particular piece of information is
+coming from.
+
Models across files
===================