diff options
| author | evildmp <daniele@vurt.org> | 2013-09-06 12:57:25 -0500 |
|---|---|---|
| committer | evildmp <daniele@vurt.org> | 2013-09-06 12:57:25 -0500 |
| commit | 79cc66692ad282b41a15fba9da9222c3140d4405 (patch) | |
| tree | 5075a090232a67f30dd2e120046652f93914bd1a /docs/ref | |
| parent | bd8e1a354cb1fde5e5411e3c729a0d179f4eb37b (diff) | |
Consolidated documentation for F() and Q()
Diffstat (limited to 'docs/ref')
| -rw-r--r-- | docs/ref/models/fields.txt | 11 | ||||
| -rw-r--r-- | docs/ref/models/index.txt | 1 | ||||
| -rw-r--r-- | docs/ref/models/instances.txt | 34 | ||||
| -rw-r--r-- | docs/ref/models/queries.txt | 127 |
4 files changed, 145 insertions, 28 deletions
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 194290581e..dd0d025ab2 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -1062,11 +1062,12 @@ define the details of how the relation works. only allows the choice of related objects with a ``pub_date`` before the current date to be chosen. - Instead of a dictionary this can also be a :class:`~django.db.models.Q` - object for more :ref:`complex queries <complex-lookups-with-q>`. However, - if ``limit_choices_to`` is a :class:`~django.db.models.Q` object then it - will only have an effect on the choices available in the admin when the - field is not listed in ``raw_id_fields`` in the ``ModelAdmin`` for the model. + Instead of a dictionary this can also be a :class:`Q object + <django.db.models.Q>` for more :ref:`complex queries + <complex-lookups-with-q>`. However, if ``limit_choices_to`` is a :class:`Q + object <django.db.models.Q>` then it will only have an effect on the + choices available in the admin when the field is not listed in + ``raw_id_fields`` in the ``ModelAdmin`` for the model. .. attribute:: ForeignKey.related_name diff --git a/docs/ref/models/index.txt b/docs/ref/models/index.txt index b5896c35ed..c61bb35a5f 100644 --- a/docs/ref/models/index.txt +++ b/docs/ref/models/index.txt @@ -12,3 +12,4 @@ Model API reference. For introductory material, see :doc:`/topics/db/models`. options instances querysets + queries diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index 3ad22fbb12..6bc6917a9e 100644 --- a/docs/ref/models/instances.txt +++ b/docs/ref/models/instances.txt @@ -342,6 +342,8 @@ only. Using ``update_fields`` will force an update similarly to ``force_update``. +.. _ref-models-field-updates-using-f-expressions: + Updating attributes based on existing fields -------------------------------------------- @@ -356,35 +358,21 @@ achieve this is to do something like:: If the old ``number_sold`` value retrieved from the database was 10, then the value of 11 will be written back to the database. -This sequence has a standard update problem in that it contains a race -condition. If another thread of execution has already saved an updated value -after the current thread retrieved the old value, the current thread will only -save the old value plus one, rather than the new (current) value plus one. - -The process can be made robust and slightly faster by expressing the update -relative to the original field value, rather than as an explicit assignment of -a new value. Django provides :ref:`F() expressions <query-expressions>` for -performing this kind of relative update. Using ``F()`` expressions, the -previous example is expressed as:: +The process can be made robust, :ref:`avoiding a race condition +<avoiding-race-conditions-using-f>`, as well as slightly faster by expressing +the update relative to the original field value, rather than as an explicit +assignment of a new value. Django provides :class:`F expressions +<django.db.models.F>` for performing this kind of relative update. Using +:class:`F expressions <django.db.models.F>`, the previous example is expressed +as:: >>> from django.db.models import F >>> product = Product.objects.get(name='Venezuelan Beaver Cheese') >>> product.number_sold = F('number_sold') + 1 >>> product.save() -This approach doesn't use the initial value from the database. Instead, it -makes the database do the update based on whatever value is current at the time -that the :meth:`~Model.save()` is executed. - -Once the object has been saved, you must reload the object in order to access -the actual value that was applied to the updated field:: - - >>> product = Products.objects.get(pk=product.pk) - >>> print(product.number_sold) - 42 - -For more details, see the documentation on :ref:`F() expressions -<query-expressions>` and their :ref:`use in update queries +For more details, see the documentation on :class:`F expressions +<django.db.models.F>` and their :ref:`use in update queries <topics-db-queries-update>`. Specifying which fields to save diff --git a/docs/ref/models/queries.txt b/docs/ref/models/queries.txt new file mode 100644 index 0000000000..ebc5142b30 --- /dev/null +++ b/docs/ref/models/queries.txt @@ -0,0 +1,127 @@ +===================== +Query-related classes +===================== + +.. currentmodule:: django.db.models + +This document provides reference material for query-related tools not +documented elsewhere. + +``F()`` expressions +=================== + +.. class:: F + +An ``F()`` object represents the value of a model field. It makes it possible +to refer to model field values and perform database operations using them +without actually having to pull them out of the database into Python memory. + +Instead, Django uses the ``F()`` object to generate a SQL expression that +describes the required operation at the database level. + +This is easiest to understand though an example. Normally, one might do +something like this:: + + # Tintin filed a news story! + reporter = Reporters.objects.get(name='Tintin') + reporter.stories_filed += 1 + reporter.save() + +Here, we have pulled the value of ``reporter.stories_filed`` from the database +into memory and manipulated it using familiar Python operators, and then saved +the object back to the database. But instead we could also have done:: + + from django.db.models import F + reporter = Reporters.objects.get(name='Tintin') + reporter.stories_filed = F('stories_filed') + 1 + reporter.save() + +Although ``reporter.stories_filed = F('stories_filed') + 1`` looks like a +normal Python assignment of value to an instance attribute, in fact it's an SQL +construct describing an operation on the database. + +When Django encounters an instance of ``F()``, it overrides the standard Python +operators to create an encapsulated SQL expression; in this case, one which +instructs the database to increment the database field represented by +``reporter.stories_filed``. + +Whatever value is or was on ``reporter.stories_filed``, Python never gets to +know about it - it is dealt with entirely by the database. All Python does, +through Django's ``F()`` class, is create the SQL syntax to refer to the field +and describe the operation. + +.. note:: + + In order to access the new value that has been saved in this way, the object + will need to be reloaded:: + + reporter = Reporters.objects.get(pk=reporter.pk) + +As well as being used in operations on single instances as above, ``F()`` can +be used on ``QuerySets`` of object instances, with ``update()``. This reduces +the two queries we were using above - the ``get()`` and the +:meth:`~Model.save()` - to just one:: + + reporter = Reporters.objects.filter(name='Tintin') + reporter.update(stories_filed=F('stories_filed') + 1) + +We can also use :meth:`~django.db.models.query.QuerySet.update()` to increment +the field value on multiple objects - which could be very much faster than +pulling them all into Python from the database, looping over them, incrementing +the field value of each one, and saving each one back to the database:: + + Reporter.objects.all().update(stories_filed=F('stories_filed) + 1) + +``F()`` therefore can offer performance advantages by: + +* getting the database, rather than Python, to do work +* reducing the number of queries some operations require + +.. _avoiding-race-conditions-using-f: + +Avoiding race conditions using ``F()`` +-------------------------------------- + +Another useful benefit of ``F()`` is that having the database - rather than +Python - update a field's value avoids a *race condition*. + +If two Python threads execute the code in the first example above, one thread +could retrieve, increment, and save a field's value after the other has +retrieved it from the database. The value that the second thread saves will be +based on the original value; the work of the first thread will simply be lost. + +If the database is responsible for updating the field, the process is more +robust: it will only ever update the field based on the value of the field in +the database when the :meth:`~Model.save()` or ``update()`` is executed, rather +than based on its value when the instance was retrieved. + +Using ``F()`` in filters +------------------------ + +``F()`` is also very useful in ``QuerySet`` filters, where they make it +possible to filter a set of objects against criteria based on their field +values, rather than on Python values. + +This is documented in :ref:`using F() expressions in queries +<using-f-expressions-in-filters>` + +Supported operations with ``F()`` +--------------------------------- + +As well as addition, Django supports subtraction, multiplication, division, +and modulo arithmetic with ``F()`` objects, using Python constants, +variables, and even other ``F()`` objects. + +``Q()`` objects +=============== + +.. class:: Q + +A ``Q()`` object, like an :class:`~django.db.models.F` object, encapsulates a +SQL expression in a Python object that can be used in database-related +operations. + +In general, ``Q() objects`` make it possible to define and reuse conditions. +This permits the :ref:`construction of complex database queries +<complex-lookups-with-q>` using ``|`` (``OR``) and ``&`` (``AND``) operators; +in particular, it is not otherwise possible to use ``OR`` in ``QuerySets``. |
