Be very clear about when it's appropriate to use defer() and only().

I've been seeing a bit of over-reliance on defer() and only() in code
around the place and it's generally better modelled with normalised data
or shadow (unmanaged) models. This commit makes this position clearer.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16692 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2011-08-26 06:19:30 +00:00
parent 499f01842e
commit 70e59aeaf8
2 changed files with 35 additions and 18 deletions

View File

@ -91,7 +91,8 @@ Django quotes column and table names behind the scenes.
Defaults to ``True``, meaning Django will create the appropriate database
tables in :djadmin:`syncdb` and remove them as part of a :djadmin:`reset`
management command. That is, Django *manages* the database tables' lifecycles.
management command. That is, Django *manages* the database tables'
lifecycles.
If ``False``, no database table creation or deletion operations will be
performed for this model. This is useful if the model represents an existing
@ -99,21 +100,21 @@ Django quotes column and table names behind the scenes.
the *only* difference when ``managed=False``. All other aspects of
model handling are exactly the same as normal. This includes
1. Adding an automatic primary key field to the model if you don't declare
it. To avoid confusion for later code readers, it's recommended to
specify all the columns from the database table you are modeling when
using unmanaged models.
1. Adding an automatic primary key field to the model if you don't
declare it. To avoid confusion for later code readers, it's
recommended to specify all the columns from the database table you
are modeling when using unmanaged models.
2. If a model with ``managed=False`` contains a
:class:`~django.db.models.ManyToManyField` that points to another
unmanaged model, then the intermediate table for the many-to-many join
will also not be created. However, the intermediary table between one
managed and one unmanaged model *will* be created.
2. If a model with ``managed=False`` contains a
:class:`~django.db.models.ManyToManyField` that points to another
unmanaged model, then the intermediate table for the many-to-many
join will also not be created. However, the intermediary table
between one managed and one unmanaged model *will* be created.
If you need to change this default behavior, create the intermediary
table as an explicit model (with ``managed`` set as needed) and use the
:attr:`ManyToManyField.through` attribute to make the relation use your
custom model.
If you need to change this default behavior, create the intermediary
table as an explicit model (with ``managed`` set as needed) and use
the :attr:`ManyToManyField.through` attribute to make the relation
use your custom model.
For tests involving models with ``managed=False``, it's up to you to ensure
the correct tables are created as part of the test setup.

View File

@ -906,9 +906,21 @@ eventually).
analyzed your queries closely and understand *exactly* what information
you need and have measured that the difference between returning the
fields you need and the full set of fields for the model will be
significant. When you are initially developing your applications, don't
bother using ``defer()``; leave it until your query construction has
settled down and you understand where the hot-points are.
significant.
Even if you think you are in the advanced use-case situation, **only use
defer() when you cannot, at queryset load time, determine if you will need
the extra fields or not**. If you are frequently loading and using a
particular subset of your data, the best choice you can make is to
normalize your models and put the non-loaded data into a separate model
(and database table). If the columns *must* stay in the one table for some
reason, create a model with ``Meta.managed = False`` (see the
:py:attr:`managed attribute <django.db.models.Options.managed>`
documentation) containing just the fields you normally need to load and use
that where you might otherwise call ``defer()``. This makes your code more
explicit to the reader, is slightly faster and consumes a little less
memory in the Python process.
only
~~~~
@ -946,6 +958,10 @@ logically::
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")
All of the cautions in the note for the :py:meth:`defer` documentation apply to
``only()`` as well. Use it cautiously and only after exhausting your other
options.
using
~~~~~