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:
parent
27f9b96fa0
commit
78ca7a6c07
|
@ -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.
|
||||
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
|
||||
|
||||
|
@ -883,8 +886,27 @@ that control how the relationship functions.
|
|||
``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
|
||||
recommend you use them. If that doesn't scare you away, however,
|
||||
:class:`OneToOneField` takes the same options that :class:`ForeignKey` does.
|
||||
A one-to-one relationship. Conceptually, this is similar to a
|
||||
:class:`ForeignKey` with :attr:`unique=True <Field.unique>`, but the
|
||||
"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.
|
||||
|
|
|
@ -4,13 +4,21 @@
|
|||
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
|
||||
==========================
|
||||
|
||||
.. currentmodule:: django.db.models
|
||||
|
||||
``abstract``
|
||||
------------
|
||||
|
||||
.. attribute:: Options.abstract
|
||||
|
||||
If ``True``, this model will be an :ref:`abstract base class <abstract-base-classes>`.
|
||||
|
||||
``db_table``
|
||||
------------
|
||||
|
||||
|
|
|
@ -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
|
||||
the :meth:`~QuerySet.extra` lookup method, which lets you add custom SQL to a
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue