Ticket #4234: 4234.2.diff

File 4234.2.diff, 10.6 KB (added by James Bennett, 17 years ago)

New patch with note about cascading delete of generic relations

  • docs/contenttypes.txt

     
     1==========================
     2The contenttypes framework
     3==========================
     4
     5
     6Django includes a "contenttypes" application which can track all of
     7the models installed in your Django-powered project, providing a
     8high-level, generic interface for working with your models.
     9
     10
     11Overview
     12========
     13
     14At the heart of the contenttypes application is the ``ContentType``
     15model, which lives at
     16``django.contrib.contenttypes.models.ContentType``; instances of
     17``ContentType`` represent and store information about the models
     18installed in your project, and new instances of ``ContentType`` are
     19automatically created whenever new models are installed.
     20
     21Instances of ``ContentType`` have methods for returning the model
     22classes they represent and for querying objects from those models.
     23``ContentType`` also has a `custom manager`_ which adds methods for
     24working with ``ContentType`` and for obtaining instances of
     25``ContentType`` for a particular model.
     26
     27Relations between your models and ``ContentType`` can also be used to
     28enable "generic" relationships between an instance of one of your
     29models and instances of any model you have installed.
     30
     31.. _custom manager: ../model-api/#custom-managers
     32
     33
     34Installing the contenttypes framework
     35=====================================
     36
     37The contenttypes framework is included in the default
     38``INSTALLED_APPS`` list created by ``django-admin.py startproject``,
     39but if you've removed it or if you manually set up your
     40``INSTALLED_APPS`` list, you can enable it by adding
     41``django.contrib.contenttypes`` to your ``INSTALLED_APPS`` setting.
     42
     43It's generally a good idea to have the contenttypes framework
     44installed; several of Django's other bundled applications require it:
     45
     46* The admin application uses it to log the history of each object
     47  added or changed through the admin interface.
     48
     49* Django's `authentication framework`_ uses it to tie user permissions
     50  to specific models.
     51
     52* Django's comments system (``django.contrib.comments``) uses it to
     53  "attach" comments to any installed model.
     54
     55.. _authentication framework: ../authentication/
     56
     57
     58The ``ContentType`` model
     59=========================
     60
     61Each instance of ``ContentType`` has three fields which, taken
     62together, uniquely describe an installed model:
     63
     64    ``app_label``
     65        The name of the application the model is part of. This is
     66        taken from the ``app_label`` attribute of the model's ``Meta``
     67        class, and includes only the *last* part of the application's
     68        Python import path; "django.contrib.contenttypes", for
     69        example, becomes an ``app_label`` of "contenttypes".
     70
     71    ``model``
     72        The name of the model class.
     73
     74    ``name``
     75        The human-readable name of the model. This is taken from `the
     76        verbose_name attribute`_ of the model's ``Meta`` class.
     77
     78Let's look at an example to see how this works. If you already have
     79the contenttypes application installed, and then add `the sites
     80application`_ to your ``INSTALLED_APPS`` setting and run ``manage.py
     81syncdb`` to install it, the model ``django.contrib.sites.models.Site``
     82will be installed into your database. Along with it a new instance
     83of ``ContentType`` will be created with the following values:
     84
     85* ``app_label`` will be set to ``sites`` (the last part of the Python
     86  path "django.contrib.sites").
     87
     88* ``model`` will be set to "site".
     89
     90* ``name`` will be set to "site".
     91
     92.. _the verbose_name attribute: ../model-api/#verbose_name
     93.. _the sites application: ../sites/
     94
     95
     96Methods on ``ContentType`` instances
     97====================================
     98
     99Additionally, each ``ContentType`` instance has methods which allow
     100you to easily get from a ``ContentType`` instance to the model it
     101represents, or to retrieve objects from that model:
     102
     103    ``get_object_for_this_type(**kwargs)``
     104        Takes a set of valid `lookup arguments`_ for the model the
     105        ``ContentType`` represents, and does `a get() lookup`_ on that
     106        model, returning the corresponding object.
     107
     108    ``model_class()``
     109        Returns the model class represented by this ``ContentType``
     110        instance.
     111
     112So, for example, we could look up the ``ContentType`` for the ``User``
     113model::
     114
     115    >>> from django.contrib.contenttypes.models import ContentType
     116    >>> user_type = ContentType.objects.get(app_label="auth", model="user")
     117    >>> user_type
     118    <ContentType: user>
     119
     120And then use it to query for a particular ``User``, or to get access
     121to the ``User`` model class::
     122
     123    >>> user_type.model_class()
     124    <class 'django.contrib.auth.models.User'>
     125    >>> user_type.get_object_for_this_type(username='Guido')
     126    <User: Guido>
     127
     128Together, ``get_object_for_this_type`` and ``model_class`` enable two
     129extremely important use cases:
     130
     1311. Using these methods, you can write high-level generic code which
     132   performs queries on any installed model -- instead of importing and
     133   using a single specific model class, you can pass an ``app_label``
     134   and ``model`` into a ``ContentType`` lookup at runtime, and then
     135   work with the model class or retrieve objects from it.
     136
     1372. You can relate another model to ``ContentType`` as a way of tying
     138   instances of it to particular model classes, and use these methods
     139   to get access to those model classes.
     140
     141Several of Django's bundled applications make use of the latter
     142technique. For example, `the permissions system`_ in Django's
     143authentication framework uses a ``Permission`` model with a foreign
     144key to ``ContentType``; this lets ``Permission`` represent concepts
     145like "can add blog entry" or "can delete news story".
     146
     147.. _lookup arguments: ../db-api/#field-lookups
     148.. _a get() lookup: ../db-api/#get-kwargs
     149.. _the permissions system: ../authentication/#permissions
     150
     151The ``ContentTypeManager``
     152--------------------------
     153
     154``ContentType`` also has a custom manager, ``ContentTypeManager``,
     155which adds the following methods:
     156
     157    ``clear_cache()``
     158        Clears an internal cache used by ``ContentType`` to keep track
     159        of which models it's created ``ContentType`` instances
     160        for. You probably won't ever need to call this method
     161        yourself; Django will call it automatically when it's needed.
     162
     163    ``get_for_model(model)``
     164        Takes either a model class or an instance of a model, and
     165        returns the ``ContentType`` instance which represents that
     166        model.
     167
     168The ``get_for_model`` method is especially useful when you know you
     169need to work with a ``ContentType`` but don't want to go to the
     170trouble of obtaining the model's metadata to perform a manual lookup::
     171
     172    >>> from django.contrib.auth.models import User
     173    >>> user_type = ContentType.objects.get_for_model(User)
     174    >>> user_type
     175    <ContentType: user>
     176
     177
     178Generic relations
     179=================
     180
     181Adding a foreign key from one of your own models to ``ContentType``
     182allows your model to effectively tie itself to another model class, as
     183in the example of the ``Permission`` model above, but it's possible to
     184go one step further and use ``ContentType`` to enable truly generic
     185(sometimes called "polymorphic") relationships between models.
     186
     187A simple example is a tagging system, which might look like this::
     188
     189    from django.db import models
     190    from django.contrib.contenttypes.models import ContentType
     191    from django.contrib.contenttypes import generic
     192   
     193    class TaggedItem(models.Model):
     194        tag = models.SlugField()
     195        content_type = models.ForeignKey(ContentType)
     196        object_id = models.PositiveIntegerField()
     197        content_object = generic.GenericForeignKey('content_type', 'object_id')
     198       
     199        def __unicode__(self):
     200            return self.tag
     201
     202A normal ``ForeignKey`` can only "point to" one other model, which
     203means that if the ``TaggedItem`` model used a ``ForeignKey`` it would have to
     204choose one and only one model to store tags for. The contenttypes
     205application provides a special field type --
     206``django.contrib.contenttypes.generic.GenericForeignKey`` -- which
     207works around this and allows the relationship to be with any
     208model. There are three parts to setting up a ``GenericForeignKey``:
     209
     2101. Give your model a ``ForeignKey`` to ``ContentType``.
     211
     2122. Add a field to your model which can store a primary-key value from
     213   the models you'll be relating to (for most models, this means an
     214   ``IntegerField`` or ``PositiveIntegerField``).
     215
     2163. Add a ``GenericForeignKey`` to your model, and pass it the names of
     217   the two fields described above. If these fields are named
     218   "content_type" and "object_id", you can omit this -- those are the
     219   default field names ``GenericForeignKey`` will look for.
     220
     221This will enable an API similar to the one used for a normal
     222``ForeignKey``; each ``TaggedItem`` will have a ``content_object``
     223field which returns the object it's related to, and you can also
     224assign to that field or use it when creating a ``TaggedItem``::
     225
     226    >>> from django.contrib.models.auth import User
     227    >>> guido = User.objects.get(username='Guido')
     228    >>> t = TaggedItem(content_object=guido, tag='bdfl')
     229    >>> t.save()
     230    >>> t.content_object
     231    <User: Guido>
     232
     233Reverse generic relations
     234-------------------------
     235
     236If you know which models you'll be using most often, you can also add
     237a "reverse" generic relationship to enable an additional API. For
     238example::
     239
     240    class Bookmark(models.Model):
     241        url = models.URLField()
     242        tags = generic.GenericRelation(TaggedItem)
     243
     244``Bookmark`` instances will each have a ``tags`` attribute which can
     245be used to retrieve their associated ``TaggedItems``::
     246
     247    >>> b = Bookmark('http://www.djangoproject.com/')
     248    >>> b.save()
     249    >>> t1 = TaggedItem(content_object=b, tag='django')
     250    >>> t1.save()
     251    >>> t2 = TaggedItem(content_object=b, tag='python')
     252    >>> t2.save()
     253    >>> b.tags.all()
     254    [<TaggedItem: django>, <TaggedItem: python>]
     255
     256If you don't add the reverse relationship, you can simply perform the
     257lookup manually::
     258
     259    >>> b = Bookmark.objects.get(url='http://www.djangoproject.com/)
     260    >>> bookmark_type = ContentType.objects.get_for_model(b)
     261    >>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id,
     262    ...                           object_id=b.id)
     263    [<TaggedItem: django>, <TaggedItem: python>]
     264
     265Note that if you delete an object which has a ``GenericRelation``,
     266any objects which have a ``GenericForeignKey`` pointing at it will be
     267deleted as well; in the example above, this means that if a
     268``Bookmark`` object were deleted, any ``TaggedItem`` objects pointing
     269at it would be deleted at the same time.
Back to Top