Ticket #4102: update_fields_django-1.4-2.patch
File update_fields_django-1.4-2.patch, 9.0 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 of fields to update explicitly specified in the ``save()`` method. 128 126 129 post_save 127 130 --------- 128 131 … … 154 157 ``using`` 155 158 The database alias being used. 156 159 160 ``update_fields`` 161 List of fields to update explicitly specified in the ``save()`` method. 162 157 163 pre_delete 158 164 ---------- 159 165 -
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 337 350 Deleting objects 338 351 ================ 339 352 -
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 self.save_base(using=using, force_insert=force_insert, 471 force_update=force_update, update_fields=update_fields) 472 465 473 save.alters_data = True 466 474 467 475 def save_base(self, raw=False, cls=None, origin=None, force_insert=False, 468 force_update=False, using=None ):476 force_update=False, using=None, update_fields=None): 469 477 """ 470 478 Does the heavy-lifting involved in saving. Subclasses shouldn't need to 471 479 override this method. It's separate from save() in order to hide the … … 483 491 meta = cls._meta 484 492 485 493 if origin and not meta.auto_created: 486 signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using) 494 signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using, 495 update_fields=update_fields) 487 496 488 497 # If we are in a raw save, save the object exactly as presented. 489 498 # That means that we don't try to be smart about saving attributes … … 503 512 if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None: 504 513 setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) 505 514 506 self.save_base(cls=parent, origin=org, using=using )515 self.save_base(cls=parent, origin=org, using=using, update_fields=update_fields) 507 516 508 517 if field: 509 518 setattr(self, field.attname, self._get_pk_val(parent._meta)) … … 513 522 if not meta.proxy: 514 523 non_pks = [f for f in meta.local_fields if not f.primary_key] 515 524 525 if update_fields: 526 non_pks = [f for f in non_pks if f.name in update_fields] 527 516 528 # First, try an UPDATE. If that doesn't update anything, do an INSERT. 517 529 pk_val = self._get_pk_val(meta) 518 530 pk_set = pk_val is not None … … 561 573 562 574 # Signal that the save is complete 563 575 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)576 signals.post_save.send(sender=origin, instance=self, created=(not record_exists), 577 update_fields=update_fields, raw=raw, using=using) 566 578 567 579 568 580 save_base.alters_data = True -
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 s.delete() 21 22 def test_update_field_with_inherited(self): 23 profile_boss = Profile.objects.create(name='Boss', salary=3000) 24 profile_receptionist = Profile.objects.create(name='Receptionist', salary=1000) 25 26 e1 = Employee.objects.create(name='Sara', gender='F', 27 employee_num=1, profile=profile_boss) 28 29 e1.name = 'Ian' 30 e1.gender = 'M' 31 e1.save(update_fields=['name']) 32 33 e2 = Employee.objects.get(pk=e1.pk) 34 self.assertEqual(e2.name, 'Ian') 35 self.assertEqual(e2.gender, 'F') 36 self.assertEqual(e2.profile, profile_boss) 37 38 e2.profile = profile_receptionist 39 e2.name = 'Sara' 40 e2.save(update_fields=['profile']) 41 42 e3 = Employee.objects.get(pk=e1.pk) 43 self.assertEqual(e3.name, 'Ian') 44 self.assertEqual(e3.profile, profile_receptionist) 45 46 e1.delete() 47 profile_boss.delete() 48 profile_receptionist.delete() 49 50 def test_update_field_with_incorrect_params(self): 51 s = Person.objects.create(name='Sara', gender='F') 52 53 with self.assertRaises(ValueError): 54 s.save(update_fields=['first_name']) 55 56 s.delete() -
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