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
This commit is contained in:
parent
007bfddc1f
commit
b2f72fc040
1
AUTHORS
1
AUTHORS
|
@ -439,6 +439,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
viestards.lists@gmail.com
|
viestards.lists@gmail.com
|
||||||
George Vilches <gav@thataddress.com>
|
George Vilches <gav@thataddress.com>
|
||||||
Vlado <vlado@labath.org>
|
Vlado <vlado@labath.org>
|
||||||
|
Zachary Voase <zacharyvoase@gmail.com>
|
||||||
Milton Waddams
|
Milton Waddams
|
||||||
Chris Wagner <cw264701@ohio.edu>
|
Chris Wagner <cw264701@ohio.edu>
|
||||||
Rick Wagner <rwagner@physics.ucsd.edu>
|
Rick Wagner <rwagner@physics.ucsd.edu>
|
||||||
|
|
|
@ -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
|
errors that are difficult to track down. This feature is for advanced use
|
||||||
only.
|
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
|
Deleting objects
|
||||||
================
|
================
|
||||||
|
|
||||||
|
|
|
@ -80,4 +80,43 @@ Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
FieldError: Joined field references are not permitted in this query
|
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'
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
|
Loading…
Reference in New Issue