diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2009-07-24 13:38:36 +0000 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2009-07-24 13:38:36 +0000 |
| commit | b2f72fc0405e966a5c4dbce23e84a43d80db3614 (patch) | |
| tree | 8d3ed0e75a9a8a282915562f172585dafc8d0073 | |
| parent | 007bfddc1fc4977009e431cf9706408316b682af (diff) | |
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
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | docs/ref/models/instances.txt | 42 | ||||
| -rw-r--r-- | tests/modeltests/expressions/models.py | 39 |
3 files changed, 81 insertions, 1 deletions
@@ -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> diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index c6509ece3d..7a0606dafe 100644 --- a/docs/ref/models/instances.txt +++ b/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`. diff --git a/tests/modeltests/expressions/models.py b/tests/modeltests/expressions/models.py index f29767a9d1..d4de5ccee9 100644 --- a/tests/modeltests/expressions/models.py +++ b/tests/modeltests/expressions/models.py @@ -80,4 +80,43 @@ Traceback (most recent call last): ... 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' + """} |
