mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7124 bcc190cf-cafb-0310-a4f2-bffc1f526a37
		
			
				
	
	
		
			259 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| ==========================
 | |
| 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.auth.models 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(url='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.
 |