diff options
| author | Simon Charette <charette.s@gmail.com> | 2014-01-22 01:43:33 -0500 |
|---|---|---|
| committer | Simon Charette <charette.s@gmail.com> | 2014-01-26 14:42:30 -0500 |
| commit | 10e3faf191d8f230dde8534d1c8fad8c8717816e (patch) | |
| tree | 26d597787a0a22f0f11b1d1e0daf0c3b1feb5805 /docs | |
| parent | c3881944e8651ad98e29561154186e87928ca319 (diff) | |
Fixed #19774 -- Deprecated the contenttypes.generic module.
It contained models, forms and admin objects causing undesirable
import side effects. Refs #16368.
Thanks to Ramiro, Carl and Loïc for the review.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/ref/contrib/admin/index.txt | 14 | ||||
| -rw-r--r-- | docs/ref/contrib/comments/models.txt | 4 | ||||
| -rw-r--r-- | docs/ref/contrib/contenttypes.txt | 136 | ||||
| -rw-r--r-- | docs/ref/models/querysets.txt | 4 | ||||
| -rw-r--r-- | docs/releases/1.4-alpha-1.txt | 3 | ||||
| -rw-r--r-- | docs/releases/1.4-beta-1.txt | 3 | ||||
| -rw-r--r-- | docs/releases/1.4.txt | 3 | ||||
| -rw-r--r-- | docs/releases/1.6.txt | 8 | ||||
| -rw-r--r-- | docs/releases/1.7.txt | 19 |
9 files changed, 123 insertions, 71 deletions
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 281ea4674b..14d2a69d7f 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -2187,30 +2187,32 @@ It is possible to use an inline with generically related objects. Let's say you have the following models:: from django.db import models + from django.contrib.contenttypes.fields import GenericForeignKey class Image(models.Model): image = models.ImageField(upload_to="images") content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey("content_type", "object_id") + content_object = GenericForeignKey("content_type", "object_id") class Product(models.Model): name = models.CharField(max_length=100) If you want to allow editing and creating ``Image`` instance on the ``Product`` -add/change views you can use ``GenericTabularInline`` or -``GenericStackedInline`` (both subclasses of ``GenericInlineModelAdmin``) -provided by ``django.contrib.contenttypes.generic``, they implement tabular and +add/change views you can use :class:`~django.contrib.contenttypes.admin.GenericTabularInline` +or :class:`~django.contrib.contenttypes.admin.GenericStackedInline` (both +subclasses of :class:`~django.contrib.contenttypes.admin.GenericInlineModelAdmin`) +provided by :mod:`~django.contrib.contenttypes.admin`, they implement tabular and stacked visual layouts for the forms representing the inline objects respectively just like their non-generic counterparts and behave just like any other inline. In your ``admin.py`` for this example app:: from django.contrib import admin - from django.contrib.contenttypes import generic + from django.contrib.contenttypes.admin import GenericTabularInline from myproject.myapp.models import Image, Product - class ImageInline(generic.GenericTabularInline): + class ImageInline(GenericTabularInline): model = Image class ProductAdmin(admin.ModelAdmin): diff --git a/docs/ref/contrib/comments/models.txt b/docs/ref/contrib/comments/models.txt index cae9c11971..3f9ac740bd 100644 --- a/docs/ref/contrib/comments/models.txt +++ b/docs/ref/contrib/comments/models.txt @@ -23,12 +23,12 @@ The built-in comment models .. attribute:: content_object - A :class:`~django.contrib.contenttypes.generic.GenericForeignKey` + A :class:`~django.contrib.contenttypes.fields.GenericForeignKey` attribute pointing to the object the comment is attached to. You can use this to get at the related object (i.e. ``my_comment.content_object``). Since this field is a - :class:`~django.contrib.contenttypes.generic.GenericForeignKey`, it's + :class:`~django.contrib.contenttypes.fields.GenericForeignKey`, it's actually syntactic sugar on top of two underlying attributes, described below. diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt index 58a309c17d..19c2853722 100644 --- a/docs/ref/contrib/contenttypes.txt +++ b/docs/ref/contrib/contenttypes.txt @@ -232,7 +232,7 @@ lookup:: >>> user_type <ContentType: user> -.. module:: django.contrib.contenttypes.generic +.. module:: django.contrib.contenttypes.fields .. _generic-relations: @@ -250,14 +250,14 @@ 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.fields import GenericForeignKey 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') + content_object = GenericForeignKey('content_type', 'object_id') # On Python 3: def __str__(self): def __unicode__(self): @@ -274,7 +274,7 @@ model: .. class:: GenericForeignKey There are three parts to setting up a - :class:`~django.contrib.contenttypes.generic.GenericForeignKey`: + :class:`~django.contrib.contenttypes.fields.GenericForeignKey`: 1. Give your model a :class:`~django.db.models.ForeignKey` to :class:`~django.contrib.contenttypes.models.ContentType`. The usual @@ -286,11 +286,11 @@ model: for this field is "object_id". 3. Give your model a - :class:`~django.contrib.contenttypes.generic.GenericForeignKey`, and + :class:`~django.contrib.contenttypes.fields.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 - :class:`~django.contrib.contenttypes.generic.GenericForeignKey` will + :class:`~django.contrib.contenttypes.fields.GenericForeignKey` will look for. .. attribute:: GenericForeignKey.for_concrete_model @@ -301,6 +301,10 @@ model: is ``True``. This mirrors the ``for_concrete_model`` argument to :meth:`~django.contrib.contenttypes.models.ContentTypeManager.get_for_model`. + .. versionchanged:: 1.7 + + This class used to be defined in ``django.contrib.contenttypes.generic``. + .. admonition:: Primary key type compatibility @@ -347,10 +351,10 @@ creating a ``TaggedItem``:: >>> t.content_object <User: Guido> -Due to the way :class:`~django.contrib.contenttypes.generic.GenericForeignKey` +Due to the way :class:`~django.contrib.contenttypes.fields.GenericForeignKey` is implemented, you cannot use such fields directly with filters (``filter()`` and ``exclude()``, for example) via the database API. Because a -:class:`~django.contrib.contenttypes.generic.GenericForeignKey` isn't a +:class:`~django.contrib.contenttypes.fields.GenericForeignKey` isn't a normal field object, these examples will *not* work:: # This will fail @@ -358,7 +362,7 @@ normal field object, these examples will *not* work:: # This will also fail >>> TaggedItem.objects.get(content_object=guido) -Likewise, :class:`~django.contrib.contenttypes.generic.GenericForeignKey`\s +Likewise, :class:`~django.contrib.contenttypes.fields.GenericForeignKey`\s does not appear in :class:`~django.forms.ModelForm`\s. Reverse generic relations @@ -366,12 +370,16 @@ Reverse generic relations .. class:: GenericRelation + .. versionchanged:: 1.7 + + This class used to be defined in ``django.contrib.contenttypes.generic``. + 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) + tags = GenericRelation(TaggedItem) ``Bookmark`` instances will each have a ``tags`` attribute, which can be used to retrieve their associated ``TaggedItems``:: @@ -385,10 +393,10 @@ be used to retrieve their associated ``TaggedItems``:: >>> b.tags.all() [<TaggedItem: django>, <TaggedItem: python>] -Just as :class:`~django.contrib.contenttypes.generic.GenericForeignKey` +Just as :class:`~django.contrib.contenttypes.fields.GenericForeignKey` accepts the names of the content-type and object-ID fields as arguments, so too does -:class:`~django.contrib.contenttypes.generic.GenericRelation`; +:class:`~django.contrib.contenttypes.fields.GenericRelation`; if the model which has the generic foreign key is using non-default names for those fields, you must pass the names of the fields when setting up a :class:`.GenericRelation` to it. For example, if the ``TaggedItem`` model @@ -396,9 +404,9 @@ referred to above used fields named ``content_type_fk`` and ``object_primary_key`` to create its generic foreign key, then a :class:`.GenericRelation` back to it would need to be defined like so:: - tags = generic.GenericRelation(TaggedItem, - content_type_field='content_type_fk', - object_id_field='object_primary_key') + tags = GenericRelation(TaggedItem, + content_type_field='content_type_fk', + object_id_field='object_primary_key') Of course, if you don't add the reverse relationship, you can do the same types of lookups manually:: @@ -410,29 +418,29 @@ same types of lookups manually:: [<TaggedItem: django>, <TaggedItem: python>] Note that if the model in a -:class:`~django.contrib.contenttypes.generic.GenericRelation` uses a +:class:`~django.contrib.contenttypes.fields.GenericRelation` uses a non-default value for ``ct_field`` or ``fk_field`` in its -:class:`~django.contrib.contenttypes.generic.GenericForeignKey` (e.g. the +:class:`~django.contrib.contenttypes.fields.GenericForeignKey` (e.g. the :mod:`django.contrib.comments` app uses ``ct_field="object_pk"``), you'll need to set ``content_type_field`` and/or ``object_id_field`` in -the :class:`~django.contrib.contenttypes.generic.GenericRelation` to +the :class:`~django.contrib.contenttypes.fields.GenericRelation` to match the ``ct_field`` and ``fk_field``, respectively, in the -:class:`~django.contrib.contenttypes.generic.GenericForeignKey`:: +:class:`~django.contrib.contenttypes.fields.GenericForeignKey`:: - comments = generic.GenericRelation(Comment, object_id_field="object_pk") + comments = fields.GenericRelation(Comment, object_id_field="object_pk") Note also, that if you delete an object that has a -:class:`~django.contrib.contenttypes.generic.GenericRelation`, any objects -which have a :class:`~django.contrib.contenttypes.generic.GenericForeignKey` +:class:`~django.contrib.contenttypes.fields.GenericRelation`, any objects +which have a :class:`~django.contrib.contenttypes.fields.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. Unlike :class:`~django.db.models.ForeignKey`, -:class:`~django.contrib.contenttypes.generic.GenericForeignKey` does not accept +:class:`~django.contrib.contenttypes.fields.GenericForeignKey` does not accept an :attr:`~django.db.models.ForeignKey.on_delete` argument to customize this behavior; if desired, you can avoid the cascade-deletion simply by not using -:class:`~django.contrib.contenttypes.generic.GenericRelation`, and alternate +:class:`~django.contrib.contenttypes.fields.GenericRelation`, and alternate behavior can be provided via the :data:`~django.db.models.signals.pre_delete` signal. @@ -441,7 +449,7 @@ Generic relations and aggregation :doc:`Django's database aggregation API </topics/db/aggregation>` doesn't work with a -:class:`~django.contrib.contenttypes.generic.GenericRelation`. For example, you +:class:`~django.contrib.contenttypes.fields.GenericRelation`. For example, you might be tempted to try something like:: Bookmark.objects.aggregate(Count('tags')) @@ -452,18 +460,55 @@ to the queryset to ensure the correct content type, but the into account. For now, if you need aggregates on generic relations, you'll need to calculate them without using the aggregation API. -Generic relations in forms and admin ------------------------------------- -The :mod:`django.contrib.contenttypes.generic` module provides: +.. module:: django.contrib.contenttypes.forms + +Generic relation in forms +------------------------- -* ``BaseGenericInlineFormSet`` -* :class:`~django.contrib.contenttypes.generic.GenericTabularInline` - and :class:`~django.contrib.contenttypes.generic.GenericStackedInline` - (subclasses of - :class:`~django.contrib.contenttypes.generic.GenericInlineModelAdmin`) +The :mod:`django.contrib.contenttypes.forms` module provides: + +* :class:`BaseGenericInlineFormSet` * A formset factory, :func:`generic_inlineformset_factory`, for use with - :class:`GenericForeignKey` + :class:`~django.contrib.contenttypes.fields.GenericForeignKey`. + +.. class:: BaseGenericInlineFormSet + + .. versionchanged:: 1.7 + + This class used to be defined in ``django.contrib.contenttypes.generic``. + +.. function:: generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, ct_field="content_type", fk_field="object_id", fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, validate_max=False, for_concrete_model=True) + + Returns a ``GenericInlineFormSet`` using + :func:`~django.forms.models.modelformset_factory`. + + You must provide ``ct_field`` and ``fk_field`` if they are different from + the defaults, ``content_type`` and ``object_id`` respectively. Other + parameters are similar to those documented in + :func:`~django.forms.models.modelformset_factory` and + :func:`~django.forms.models.inlineformset_factory`. + + .. versionadded:: 1.6 + + The ``for_concrete_model`` argument corresponds to the + :class:`~django.contrib.contenttypes.fields.GenericForeignKey.for_concrete_model` + argument on ``GenericForeignKey``. + + .. versionchanged:: 1.7 + + This function used to be defined in ``django.contrib.contenttypes.generic``. + + +.. module:: django.contrib.contenttypes.admin + +Generic relations in admin +------------------------------------ + +The :mod:`django.contrib.contenttypes.admin` module provides +:class:`~django.contrib.contenttypes.admin.GenericTabularInline` and +:class:`~django.contrib.contenttypes.admin.GenericStackedInline` (subclasses of +:class:`~django.contrib.contenttypes.admin.GenericInlineModelAdmin`) These classes and functions enable the use of generic relations in forms and the admin. See the :doc:`model formset </topics/forms/modelforms>` and @@ -472,7 +517,7 @@ information. .. class:: GenericInlineModelAdmin - The :class:`~django.contrib.contenttypes.generic.GenericInlineModelAdmin` + The :class:`~django.contrib.contenttypes.admin.GenericInlineModelAdmin` class inherits all properties from an :class:`~django.contrib.admin.InlineModelAdmin` class. However, it adds a couple of its own for working with the generic relation: @@ -488,25 +533,16 @@ information. The name of the integer field that represents the ID of the related object. Defaults to ``object_id``. + .. versionchanged:: 1.7 + + This class used to be defined in ``django.contrib.contenttypes.generic``. + .. class:: GenericTabularInline .. class:: GenericStackedInline Subclasses of :class:`GenericInlineModelAdmin` with stacked and tabular layouts, respectively. -.. function:: generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, ct_field="content_type", fk_field="object_id", fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, validate_max=False, for_concrete_model=True) + .. versionchanged:: 1.7 - Returns a ``GenericInlineFormSet`` using - :func:`~django.forms.models.modelformset_factory`. - - You must provide ``ct_field`` and ``fk_field`` if they are different from - the defaults, ``content_type`` and ``object_id`` respectively. Other - parameters are similar to those documented in - :func:`~django.forms.models.modelformset_factory` and - :func:`~django.forms.models.inlineformset_factory`. - - .. versionadded:: 1.6 - - The ``for_concrete_model`` argument corresponds to the - :class:`~django.contrib.contenttypes.generic.GenericForeignKey.for_concrete_model` - argument on ``GenericForeignKey``. + These classes used to be defined in ``django.contrib.contenttypes.generic``. diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 5e310e7ac3..c063d38aa6 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -798,8 +798,8 @@ relationship, and does the 'joining' in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using ``select_related``, in addition to the foreign key and one-to-one relationships that are supported by ``select_related``. It also supports prefetching of -:class:`~django.contrib.contenttypes.generic.GenericRelation` and -:class:`~django.contrib.contenttypes.generic.GenericForeignKey`. +:class:`~django.contrib.contenttypes.fields.GenericRelation` and +:class:`~django.contrib.contenttypes.fields.GenericForeignKey`. For example, suppose you have these models:: diff --git a/docs/releases/1.4-alpha-1.txt b/docs/releases/1.4-alpha-1.txt index d47f624f5b..ebd0084469 100644 --- a/docs/releases/1.4-alpha-1.txt +++ b/docs/releases/1.4-alpha-1.txt @@ -92,8 +92,7 @@ different strategy and broader scope, ``QuerySet`` that will prefetch each of the specified related lookups in a single batch as soon as the query begins to be evaluated. Unlike ``select_related``, it does the joins in Python, not in the database, and -supports many-to-many relationships, -:class:`~django.contrib.contenttypes.generic.GenericForeignKey` and more. This +supports many-to-many relationships, ``GenericForeignKey`` and more. This allows you to fix a very common performance problem in which your code ends up doing O(n) database queries (or worse) if objects on your primary ``QuerySet`` each have many related objects that you also need. diff --git a/docs/releases/1.4-beta-1.txt b/docs/releases/1.4-beta-1.txt index d670036463..674aa0e944 100644 --- a/docs/releases/1.4-beta-1.txt +++ b/docs/releases/1.4-beta-1.txt @@ -108,8 +108,7 @@ different strategy and broader scope, ``QuerySet`` that will prefetch each of the specified related lookups in a single batch as soon as the query begins to be evaluated. Unlike ``select_related``, it does the joins in Python, not in the database, and -supports many-to-many relationships, -:class:`~django.contrib.contenttypes.generic.GenericForeignKey` and more. This +supports many-to-many relationships, ``GenericForeignKey`` and more. This allows you to fix a very common performance problem in which your code ends up doing O(n) database queries (or worse) if objects on your primary ``QuerySet`` each have many related objects that you also need. diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index f8c23728b9..e59917478a 100644 --- a/docs/releases/1.4.txt +++ b/docs/releases/1.4.txt @@ -257,8 +257,7 @@ different strategy and broader scope, ``QuerySet`` that will prefetch each of the specified related lookups in a single batch as soon as the query begins to be evaluated. Unlike ``select_related``, it does the joins in Python, not in the database, and -supports many-to-many relationships, -:class:`~django.contrib.contenttypes.generic.GenericForeignKey` and more. This +supports many-to-many relationships, ``GenericForeignKey`` and more. This allows you to fix a very common performance problem in which your code ends up doing O(n) database queries (or worse) if objects on your primary ``QuerySet`` each have many related objects that you also need to fetch. diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index bbdd81a768..8407f4f097 100644 --- a/docs/releases/1.6.txt +++ b/docs/releases/1.6.txt @@ -302,11 +302,9 @@ Minor features :class:`~django.views.generic.base.RedirectView` now support HTTP ``PATCH`` method. -* :class:`GenericForeignKey <django.contrib.contenttypes.generic.GenericForeignKey>` - now takes an optional - :attr:`~django.contrib.contenttypes.generic.GenericForeignKey.for_concrete_model` - argument, which when set to ``False`` allows the field to reference proxy - models. The default is ``True`` to retain the old behavior. +* ``GenericForeignKey`` now takes an optional ``for_concrete_model`` argument, + which when set to ``False`` allows the field to reference proxy models. The + default is ``True`` to retain the old behavior. * The :class:`~django.middleware.locale.LocaleMiddleware` now stores the active language in session if it is not present there. This prevents loss of diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index e56939f3ce..305b34fe55 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -1030,6 +1030,25 @@ API, it will go through a regular deprecation path. This attribute was mostly used by methods that bypassed ``ModelAdmin.get_fieldsets()`` but this was considered a bug and has been addressed. +Reorganization of ``django.contrib.contenttypes`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since ``django.contrib.contenttypes.generic`` defined both admin and model +related objects an import of this module could trigger unexpected side effects. +As a consequence, its contents were split into :mod:`~django.contrib.contenttypes` +submodules and the ``django.contrib.contenttypes.generic`` module is deprecated: + +* :class:`~django.contrib.contenttypes.fields.GenericForeignKey` and + :class:`~django.contrib.contenttypes.fields.GenericRelation` now live in + :mod:`~django.contrib.contenttypes.fields`. +* :class:`~django.contrib.contenttypes.forms.BaseGenericInlineFormSet` and + :func:`~django.contrib.contenttypes.forms.generic_inlineformset_factory` now + live in :mod:`~django.contrib.contenttypes.forms`. +* :class:`~django.contrib.contenttypes.admin.GenericInlineModelAdmin`, + :class:`~django.contrib.contenttypes.admin.GenericStackedInline` and + :class:`~django.contrib.contenttypes.admin.GenericTabularInline` now live in + :mod:`~django.contrib.contenttypes.admin`. + ``syncdb`` ~~~~~~~~~~ |
