Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #11527 -- Added unit tests and documentation for the use of F()…

… expressions in single object updates. Thanks to Zachary Voase for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@11322 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit b2f72fc0405e966a5c4dbce23e84a43d80db3614 1 parent 007bfdd
@freakboy3742 freakboy3742 authored
View
1  AUTHORS
@@ -439,6 +439,7 @@ answer newbie questions, and generally made Django that much better:
viestards.lists@gmail.com
George Vilches <gav@thataddress.com>
Vlado <vlado@labath.org>
+ Zachary Voase <zacharyvoase@gmail.com>
Milton Waddams
Chris Wagner <cw264701@ohio.edu>
Rick Wagner <rwagner@physics.ucsd.edu>
View
42 docs/ref/models/instances.txt
@@ -188,6 +188,46 @@ almost always do the right thing and trying to override that will lead to
errors that are difficult to track down. This feature is for advanced use
only.
+Updating attributes based on existing fields
+--------------------------------------------
+
+Sometimes you'll need to perform a simple arithmetic task on a field, such
+as incrementing or decrementing the current value. The obvious way to
+achieve this is to do something like::
+
+ >>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
+ >>> product.number_sold += 1
+ >>> product.save()
+
+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 can be optimized slightly 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>` as a way of
+performing this kind of relative update. Using ``F()`` expressions, the
+previous example would be 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 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
+<topics-db-queries-update>`.
+
Deleting objects
================
@@ -196,7 +236,7 @@ Deleting objects
Issues a SQL ``DELETE`` for the object. This only deletes the object in the
database; the Python instance will still be around, and will still have data
in its fields.
-
+
For more details, including how to delete objects in bulk, see
:ref:`topics-db-queries-delete`.
View
39 tests/modeltests/expressions/models.py
@@ -80,4 +80,43 @@ def __unicode__(self):
...
FieldError: Joined field references are not permitted in this query
+# F expressions can be used to update attributes on single objects
+>>> test_gmbh = Company.objects.get(name='Test GmbH')
+>>> test_gmbh.num_employees
+32
+>>> test_gmbh.num_employees = F('num_employees') + 4
+>>> test_gmbh.save()
+>>> test_gmbh = Company.objects.get(pk=test_gmbh.pk)
+>>> test_gmbh.num_employees
+36
+
+# F expressions cannot be used to update attributes which are foreign keys, or
+# attributes which involve joins.
+>>> test_gmbh.point_of_contact = None
+>>> test_gmbh.save()
+>>> test_gmbh.point_of_contact is None
+True
+>>> test_gmbh.point_of_contact = F('ceo')
+Traceback (most recent call last):
+...
+ValueError: Cannot assign "<django.db.models.expressions.F object at ...>": "Company.point_of_contact" must be a "Employee" instance.
+
+>>> test_gmbh.point_of_contact = test_gmbh.ceo
+>>> test_gmbh.save()
+>>> test_gmbh.name = F('ceo__last_name')
+>>> test_gmbh.save()
+Traceback (most recent call last):
+...
+FieldError: Joined field references are not permitted in this query
+
+# F expressions cannot be used to update attributes on objects which do not yet
+# exist in the database
+>>> acme = Company(name='The Acme Widget Co.', num_employees=12, num_chairs=5,
+... ceo=test_gmbh.ceo)
+>>> acme.num_employees = F('num_employees') + 16
+>>> acme.save()
+Traceback (most recent call last):
+...
+TypeError: int() argument must be a string or a number, not 'ExpressionNode'
+
"""}
Please sign in to comment.
Something went wrong with that request. Please try again.