From e90eb41a4a1814ce3524fd46d97b1c32e537b9ea Mon Sep 17 00:00:00 2001
From: Adrian Holovaty <adrian@holovaty.com>
Date: Sat, 15 Sep 2007 18:29:09 +0000
Subject: [PATCH] Fixed #4234 -- Added docs/contenttypes. Thanks, ubernostrum

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6302 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 docs/contenttypes.txt | 258 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 258 insertions(+)
 create mode 100644 docs/contenttypes.txt

diff --git a/docs/contenttypes.txt b/docs/contenttypes.txt
new file mode 100644
index 0000000000..3ef83f2066
--- /dev/null
+++ b/docs/contenttypes.txt
@@ -0,0 +1,258 @@
+==========================
+The contenttypes framework
+==========================
+
+Django includes a "contenttypes" application that can track all of
+the models installed in your Django-powered project, providing a
+high-level, generic interface for working with your models.
+
+Overview
+========
+
+At the heart of the contenttypes application is the ``ContentType``
+model, which lives at
+``django.contrib.contenttypes.models.ContentType``. Instances of
+``ContentType`` represent and store information about the models
+installed in your project, and new instances of ``ContentType`` are
+automatically created whenever new models are installed.
+
+Instances of ``ContentType`` have methods for returning the model
+classes they represent and for querying objects from those models.
+``ContentType`` also has a `custom manager`_ that adds methods for
+working with ``ContentType`` and for obtaining instances of
+``ContentType`` for a particular model.
+
+Relations between your models and ``ContentType`` can also be used to
+enable "generic" relationships between an instance of one of your
+models and instances of any model you have installed.
+
+.. _custom manager: ../model-api/#custom-managers
+
+Installing the contenttypes framework
+=====================================
+
+The contenttypes framework is included in the default
+``INSTALLED_APPS`` list created by ``django-admin.py startproject``,
+but if you've removed it or if you manually set up your
+``INSTALLED_APPS`` list, you can enable it by adding
+``'django.contrib.contenttypes'`` to your ``INSTALLED_APPS`` setting.
+
+It's generally a good idea to have the contenttypes framework
+installed; several of Django's other bundled applications require it:
+
+    * The admin application uses it to log the history of each object
+      added or changed through the admin interface.
+
+    * Django's `authentication framework`_ uses it to tie user permissions
+      to specific models.
+
+    * Django's comments system (``django.contrib.comments``) uses it to
+      "attach" comments to any installed model.
+
+.. _authentication framework: ../authentication/
+
+The ``ContentType`` model
+=========================
+
+Each instance of ``ContentType`` has three fields which, taken
+together, uniquely describe an installed model:
+
+    ``app_label``
+        The name of the application the model is part of. This is taken from
+        the ``app_label`` attribute of the model, and includes only the *last*
+        part of the application's Python import path;
+        "django.contrib.contenttypes", for example, becomes an ``app_label``
+        of "contenttypes".
+
+    ``model``
+        The name of the model class.
+
+    ``name``
+        The human-readable name of the model. This is taken from
+        `the verbose_name attribute`_ of the model.
+
+Let's look at an example to see how this works. If you already have
+the contenttypes application installed, and then add `the sites
+application`_ to your ``INSTALLED_APPS`` setting and run ``manage.py
+syncdb`` to install it, the model ``django.contrib.sites.models.Site``
+will be installed into your database. Along with it a new instance
+of ``ContentType`` will be created with the following values:
+
+    * ``app_label`` will be set to ``'sites'`` (the last part of the Python
+      path "django.contrib.sites").
+
+    * ``model`` will be set to ``'site'``.
+
+    * ``name`` will be set to ``'site'``.
+
+.. _the verbose_name attribute: ../model-api/#verbose_name
+.. _the sites application: ../sites/
+
+Methods on ``ContentType`` instances
+====================================
+
+Each ``ContentType`` instance has methods that allow you to get from a
+``ContentType`` instance to the model it represents, or to retrieve objects
+from that model:
+
+    ``get_object_for_this_type(**kwargs)``
+        Takes a set of valid `lookup arguments`_ for the model the
+        ``ContentType`` represents, and does `a get() lookup`_ on that
+        model, returning the corresponding object.
+
+    ``model_class()``
+        Returns the model class represented by this ``ContentType``
+        instance.
+
+For example, we could look up the ``ContentType`` for the ``User`` model::
+
+    >>> from django.contrib.contenttypes.models import ContentType
+    >>> user_type = ContentType.objects.get(app_label="auth", model="user")
+    >>> user_type
+    <ContentType: user>
+
+And then use it to query for a particular ``User``, or to get access
+to the ``User`` model class::
+
+    >>> user_type.model_class()
+    <class 'django.contrib.auth.models.User'>
+    >>> user_type.get_object_for_this_type(username='Guido')
+    <User: Guido>
+
+Together, ``get_object_for_this_type`` and ``model_class`` enable two
+extremely important use cases:
+
+    1. Using these methods, you can write high-level generic code that
+       performs queries on any installed model -- instead of importing and
+       using a single specific model class, you can pass an ``app_label``
+       and ``model`` into a ``ContentType`` lookup at runtime, and then
+       work with the model class or retrieve objects from it.
+
+    2. You can relate another model to ``ContentType`` as a way of tying
+       instances of it to particular model classes, and use these methods
+       to get access to those model classes.
+
+Several of Django's bundled applications make use of the latter
+technique. For example, `the permissions system`_ in Django's
+authentication framework uses a ``Permission`` model with a foreign
+key to ``ContentType``; this lets ``Permission`` represent concepts
+like "can add blog entry" or "can delete news story".
+
+.. _lookup arguments: ../db-api/#field-lookups
+.. _a get() lookup: ../db-api/#get-kwargs
+.. _the permissions system: ../authentication/#permissions
+
+The ``ContentTypeManager``
+--------------------------
+
+``ContentType`` also has a custom manager, ``ContentTypeManager``,
+which adds the following methods:
+
+    ``clear_cache()``
+        Clears an internal cache used by ``ContentType`` to keep track of which
+        models for which it has created ``ContentType`` instances. You probably
+        won't ever need to call this method yourself; Django will call it
+        automatically when it's needed.
+
+    ``get_for_model(model)``
+        Takes either a model class or an instance of a model, and returns the
+        ``ContentType`` instance representing that model.
+
+The ``get_for_model`` method is especially useful when you know you
+need to work with a ``ContentType`` but don't want to go to the
+trouble of obtaining the model's metadata to perform a manual lookup::
+
+    >>> from django.contrib.auth.models import User
+    >>> user_type = ContentType.objects.get_for_model(User)
+    >>> user_type
+    <ContentType: user>
+
+Generic relations
+=================
+
+Adding a foreign key from one of your own models to ``ContentType``
+allows your model to effectively tie itself to another model class, as
+in the example of the ``Permission`` model above. But it's possible to
+go one step further and use ``ContentType`` to enable truly generic
+(sometimes called "polymorphic") relationships between models.
+
+A simple example is a tagging system, which might look like this::
+
+    from django.db import models
+    from django.contrib.contenttypes.models import ContentType
+    from django.contrib.contenttypes import generic
+
+    class TaggedItem(models.Model):
+        tag = models.SlugField()
+        content_type = models.ForeignKey(ContentType)
+        object_id = models.PositiveIntegerField()
+        content_object = generic.GenericForeignKey('content_type', 'object_id')
+
+        def __unicode__(self):
+            return self.tag
+
+A normal ``ForeignKey`` can only "point to" one other model, which
+means that if the ``TaggedItem`` model used a ``ForeignKey`` it would have to
+choose one and only one model to store tags for. The contenttypes
+application provides a special field type --
+``django.contrib.contenttypes.generic.GenericForeignKey`` -- which
+works around this and allows the relationship to be with any
+model. There are three parts to setting up a ``GenericForeignKey``:
+
+    1. Give your model a ``ForeignKey`` to ``ContentType``.
+
+    2. Give your model a field that can store a primary-key value from the
+       models you'll be relating to. (For most models, this means an
+       ``IntegerField`` or ``PositiveIntegerField``.)
+
+    3. Give your model a ``GenericForeignKey``, and pass it the names of
+       the two fields described above. If these fields are named
+       "content_type" and "object_id", you can omit this -- those are the
+       default field names ``GenericForeignKey`` will look for.
+
+This will enable an API similar to the one used for a normal ``ForeignKey``;
+each ``TaggedItem`` will have a ``content_object`` field that returns the
+object it's related to, and you can also assign to that field or use it when
+creating a ``TaggedItem``::
+
+    >>> from django.contrib.models.auth import User
+    >>> guido = User.objects.get(username='Guido')
+    >>> t = TaggedItem(content_object=guido, tag='bdfl')
+    >>> t.save()
+    >>> t.content_object
+    <User: Guido>
+
+Reverse generic relations
+-------------------------
+
+If you know which models you'll be using most often, you can also add
+a "reverse" generic relationship to enable an additional API. For example::
+
+    class Bookmark(models.Model):
+        url = models.URLField()
+        tags = generic.GenericRelation(TaggedItem)
+
+``Bookmark`` instances will each have a ``tags`` attribute, which can
+be used to retrieve their associated ``TaggedItems``::
+
+    >>> b = Bookmark('http://www.djangoproject.com/')
+    >>> b.save()
+    >>> t1 = TaggedItem(content_object=b, tag='django')
+    >>> t1.save()
+    >>> t2 = TaggedItem(content_object=b, tag='python')
+    >>> t2.save()
+    >>> b.tags.all()
+    [<TaggedItem: django>, <TaggedItem: python>]
+
+If you don't add the reverse relationship, you can do the lookup manually::
+
+    >>> b = Bookmark.objects.get(url='http://www.djangoproject.com/)
+    >>> bookmark_type = ContentType.objects.get_for_model(b)
+    >>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id,
+    ...                           object_id=b.id)
+    [<TaggedItem: django>, <TaggedItem: python>]
+
+Note that if you delete an object that has a ``GenericRelation``, any objects
+which have a ``GenericForeignKey`` pointing at it will be deleted as well. In
+the example above, this means that if a ``Bookmark`` object were deleted, any
+``TaggedItem`` objects pointing at it would be deleted at the same time.