Ticket #4102: update_fields_django-1.4-3.patch
File update_fields_django-1.4-3.patch, 9.4 KB (added by , 13 years ago) |
---|
-
docs/ref/signals.txt
123 123 ``using`` 124 124 The database alias being used. 125 125 126 ``update_fields`` 127 List or tuple of fields to update explicitly specified in the ``save()`` method. 128 ``None`` if you do not use this parameter when you call ``save()``. 129 126 130 post_save 127 131 --------- 128 132 … … 154 158 ``using`` 155 159 The database alias being used. 156 160 161 ``update_fields`` 162 List or tuple of fields to update explicitly specified in the ``save()`` method. 163 ``None`` if you do not use this parameter when you call ``save()``. 164 157 165 pre_delete 158 166 ---------- 159 167 -
docs/ref/models/instances.txt
135 135 136 136 To save an object back to the database, call ``save()``: 137 137 138 .. method:: Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS ])138 .. method:: Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None]) 139 139 140 140 .. versionadded:: 1.2 141 141 The ``using`` argument was added. … … 334 334 <query-expressions>` and their :ref:`use in update queries 335 335 <topics-db-queries-update>`. 336 336 337 Specifying which fields to save 338 ------------------------------- 339 340 If ``save()`` is passed a list of field names as keyword argument ``update_fields``, 341 only the fields named in that list will be saved to the database. This may be 342 desirable if you want to update just one or a few fields on an object, as there 343 will be a slight performance benefit from preventing all of the model fields 344 from being updated in the database. For example: 345 346 product.name = 'Name changed again' 347 product.save(update_fields=['name']) 348 349 350 ``update_fields`` must be a list, tuple or None. And this parameter implies ``force_update=True``. 351 352 337 353 Deleting objects 338 354 ================ 339 355 -
django/db/models/signals.py
5 5 pre_init = Signal(providing_args=["instance", "args", "kwargs"]) 6 6 post_init = Signal(providing_args=["instance"]) 7 7 8 pre_save = Signal(providing_args=["instance", "raw", "using" ])9 post_save = Signal(providing_args=["instance", "raw", "created", "using" ])8 pre_save = Signal(providing_args=["instance", "raw", "using", "update_fields"]) 9 post_save = Signal(providing_args=["instance", "raw", "created", "using", "update_fields"]) 10 10 11 11 pre_delete = Signal(providing_args=["instance", "using"]) 12 12 post_delete = Signal(providing_args=["instance", "using"]) -
django/db/models/base.py
449 449 return getattr(self, field_name) 450 450 return getattr(self, field.attname) 451 451 452 def save(self, force_insert=False, force_update=False, using=None ):452 def save(self, force_insert=False, force_update=False, using=None, update_fields=None): 453 453 """ 454 454 Saves the current instance. Override this in a subclass if you want to 455 455 control the saving process. … … 460 460 """ 461 461 if force_insert and force_update: 462 462 raise ValueError("Cannot force both insert and updating in model saving.") 463 self.save_base(using=using, force_insert=force_insert, force_update=force_update) 463 464 if update_fields: 465 field_names = self._meta.get_all_field_names() 466 for field_name in update_fields: 467 if field_name not in field_names: 468 raise ValueError("%s field does not exist in this model" % (field_name)) 464 469 470 force_update = True 471 472 self.save_base(using=using, force_insert=force_insert, 473 force_update=force_update, update_fields=update_fields) 474 465 475 save.alters_data = True 466 476 467 477 def save_base(self, raw=False, cls=None, origin=None, force_insert=False, 468 force_update=False, using=None ):478 force_update=False, using=None, update_fields=None): 469 479 """ 470 480 Does the heavy-lifting involved in saving. Subclasses shouldn't need to 471 481 override this method. It's separate from save() in order to hide the … … 483 493 meta = cls._meta 484 494 485 495 if origin and not meta.auto_created: 486 signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using) 496 signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using, 497 update_fields=update_fields) 487 498 488 499 # If we are in a raw save, save the object exactly as presented. 489 500 # That means that we don't try to be smart about saving attributes … … 503 514 if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None: 504 515 setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) 505 516 506 self.save_base(cls=parent, origin=org, using=using )517 self.save_base(cls=parent, origin=org, using=using, update_fields=update_fields) 507 518 508 519 if field: 509 520 setattr(self, field.attname, self._get_pk_val(parent._meta)) … … 513 524 if not meta.proxy: 514 525 non_pks = [f for f in meta.local_fields if not f.primary_key] 515 526 527 if update_fields: 528 non_pks = [f for f in non_pks if f.name in update_fields] 529 516 530 # First, try an UPDATE. If that doesn't update anything, do an INSERT. 517 531 pk_val = self._get_pk_val(meta) 518 532 pk_set = pk_val is not None … … 561 575 562 576 # Signal that the save is complete 563 577 if origin and not meta.auto_created: 564 signals.post_save.send(sender=origin, instance=self, 565 created=(not record_exists), raw=raw, using=using)578 signals.post_save.send(sender=origin, instance=self, created=(not record_exists), 579 update_fields=update_fields, raw=raw, using=using) 566 580 567 581 568 582 save_base.alters_data = True -
tests/modeltests/update_only_fields/__init__.py
1 # -*- coding: utf-8 -*- 2 3 -
tests/modeltests/update_only_fields/tests.py
1 from __future__ import absolute_import 2 from __future__ import with_statement 3 4 from django.test import TestCase 5 from .models import Person, Employee, Profile 6 7 class UpdateOnlyFieldsTests(TestCase): 8 def test_simple_update_fields(self): 9 s = Person.objects.create(name='Sara', gender='F') 10 self.assertEqual(s.gender, 'F') 11 12 s.gender = 'M' 13 s.name = 'Ian' 14 s.save(update_fields=['name']) 15 16 s = Person.objects.get(pk=s.pk) 17 self.assertEqual(s.gender, 'F') 18 self.assertEqual(s.name, 'Ian') 19 20 def test_update_field_with_inherited(self): 21 profile_boss = Profile.objects.create(name='Boss', salary=3000) 22 profile_receptionist = Profile.objects.create(name='Receptionist', salary=1000) 23 24 e1 = Employee.objects.create(name='Sara', gender='F', 25 employee_num=1, profile=profile_boss) 26 27 e1.name = 'Ian' 28 e1.gender = 'M' 29 e1.save(update_fields=['name']) 30 31 e2 = Employee.objects.get(pk=e1.pk) 32 self.assertEqual(e2.name, 'Ian') 33 self.assertEqual(e2.gender, 'F') 34 self.assertEqual(e2.profile, profile_boss) 35 36 e2.profile = profile_receptionist 37 e2.name = 'Sara' 38 e2.save(update_fields=['profile']) 39 40 e3 = Employee.objects.get(pk=e1.pk) 41 self.assertEqual(e3.name, 'Ian') 42 self.assertEqual(e3.profile, profile_receptionist) 43 44 def test_update_field_with_incorrect_params(self): 45 s = Person.objects.create(name='Sara', gender='F') 46 47 with self.assertRaises(ValueError): 48 s.save(update_fields=['first_name']) -
tests/modeltests/update_only_fields/models.py
1 2 from django.db import models 3 4 GENDER_CHOICES = ( 5 ('M', 'Male'), 6 ('F', 'Female'), 7 ) 8 9 class Person(models.Model): 10 name = models.CharField(max_length=20) 11 gender = models.CharField(max_length=1, choices=GENDER_CHOICES) 12 13 def __unicode__(self): 14 return self.name 15 16 class Employee(Person): 17 employee_num = models.IntegerField(default=0) 18 profile = models.ForeignKey('Profile', related_name='profiles') 19 20 21 class Profile(models.Model): 22 name = models.CharField(max_length=200) 23 salary = models.FloatField(default=1000.0) 24 25 def __unicode__(self): 26 return self.name