Fixed #8533: restored model inheritance docs, and updated one-to-one docs to match

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8757 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
James Bennett 2008-08-31 10:13:32 +00:00
parent 27f9b96fa0
commit 78ca7a6c07
3 changed files with 285 additions and 6 deletions

View File

@ -811,7 +811,10 @@ define the details of how the relation works.
The name to use for the relation from the related object back to this one. The name to use for the relation from the related object back to this one.
See the :ref:`related objects documentation <backwards-related-objects>` for See the :ref:`related objects documentation <backwards-related-objects>` for
a full explanation and example. a full explanation and example. Note that you must set this value
when defining relations on :ref:`abstract models
<abstract-base-classes>`; and when you do so
:ref:`some special syntax <abstract-related-name>` is available.
.. attribute:: ForeignKey.to_field .. attribute:: ForeignKey.to_field
@ -883,8 +886,27 @@ that control how the relationship functions.
``OneToOneField`` ``OneToOneField``
----------------- -----------------
.. class:: OneToOneField(othermodel, [**options]) .. class:: OneToOneField(othermodel, [parent_link=False, **options])
The semantics of one-to-one relationships will be changing soon, so we don't A one-to-one relationship. Conceptually, this is similar to a
recommend you use them. If that doesn't scare you away, however, :class:`ForeignKey` with :attr:`unique=True <Field.unique>`, but the
:class:`OneToOneField` takes the same options that :class:`ForeignKey` does. "reverse" side of the relation will directly return a single object.
This is most useful as the primary key of a model which "extends"
another model in some way; :ref:`multi-table-inheritance` is
implemented by adding an implicit one-to-one relation from the child
model to the parent model, for example.
One positional argument is required: the class to which the model will
be related.
Additionally, ``OneToOneField`` accepts all of the extra arguments
accepted by :class:`ForeignKey`, plus one extra argument:
.. attribute: OneToOneField.parent_link
When ``True`` and used in a model which inherits from another
(concrete) model, indicates that this field should be used as the
link back to the parent class, rather than the extra
``OneToOneField`` which would normally be implicitly created by
subclassing.

View File

@ -4,13 +4,21 @@
Model ``Meta`` options Model ``Meta`` options
====================== ======================
This document explains all the possible :ref:`metadata options <meta-options>` that you can give your model in its internal ``class Meta``. This document explains all the possible :ref:`metadata options <meta-options>` that you can give your model in its internal
``class Meta``.
Available ``Meta`` options Available ``Meta`` options
========================== ==========================
.. currentmodule:: django.db.models .. currentmodule:: django.db.models
``abstract``
------------
.. attribute:: Options.abstract
If ``True``, this model will be an :ref:`abstract base class <abstract-base-classes>`.
``db_table`` ``db_table``
------------ ------------

View File

@ -747,3 +747,252 @@ 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 use A final note: If all you want to do is a custom ``WHERE`` clause, you can use
the :meth:`~QuerySet.extra` lookup method, which lets you add custom SQL to a the :meth:`~QuerySet.extra` lookup method, which lets you add custom SQL to a
query. query.
.. _model-inheritance:
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
:ref:`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, :ref:`multi-table-inheritance` is the way to go.
.. _abstract-base-classes:
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 :ref:`Meta <meta-options>`
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, and cannot be instantiated or saved directly.
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 :ref:`Meta <meta-options>`
inner class you declared on the base class available as an
attribute. If a child class does not declared its own :ref:`Meta <meta-options>`
class, it will inherit the parent's :ref:`Meta <meta-options>`. If the child wants to
extend the parent's :ref:`Meta <meta-options>` 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 :ref:`Meta <meta-options>` class of an abstract base
class: before installing the :ref:`Meta <meta-options>` 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 :ref:`Meta <meta-options>` 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 :ref:`Meta <meta-options>`) would use
the same database table, which is almost certainly not what you want.
.. _abstract-related-name:
Be careful with ``related_name``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are using the :attr:`~django.db.models.ForeignKey.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 :attr:`~django.db.models.ForeignKey.related_name`) each time.
To work around this problem, when you are using :attr:`~django.db.models.ForeignKey.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 :djadmin:`syncdb`).
If you don't specify a :attr:`~django.db.models.ForeignKey.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 :attr:`~django.db.models.ForeignKey.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:
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 :class`~django.db.models.fields.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 :ref:`Meta <meta-options>` class. All the :ref:`Meta <meta-options>` 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 :ref:`Meta <meta-options>` class. However,
there are a few limited cases where the child inherits behaviour from the
parent: if the child does not specify an :attr:`django.db.models.Options.ordering` attribute or a
:attr:`django.db.models.Options.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
:class:`~django.db.models.fields.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 :attr:`~django.db.models.ForeignKey.related_name` value for
:class:`django.db.models.fields.ForeignKey` and
:class:`django.db.models.fields.ManyToManyField` relations. If you
are putting those types of relations on a subclass of another model,
you **must** specify the
:attr:`~django.db.models.ForeignKey.related_name` attribute on each
such field. If you forget, Django will raise an error when you run
:djadmin:`validate` or :djadmin:`syncdb`.
For example, using the above ``Place`` class again, let's create another
subclass with a :class:`~django.db.models.fields.ManyToManyField`::
class Supplier(Place):
# Must specify related_name on all relations.
customers = models.ManyToManyField(Restaurant,
related_name='provider')
Specifying the parent link field
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As mentioned, Django will automatically create a
:class:`~django.db.models.fields.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 :class:`~django.db.models.fields.OneToOneField` and set
:attr:`parent_link=True <django.db.models.fields.OneToOneField.parent_link>`
to indicate that your field is the link back to the parent class.
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.
:ref:`Meta <meta-options>`) will be the one that is used; for example,
his means that if multiple parents contain a :ref:`Meta <meta-options>` class, only
the first one is going to be used, and 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.