Code

Ticket #4102: 4102-only-udpate-fields.patch

File 4102-only-udpate-fields.patch, 4.1 KB (added by Paul Smith <paulsmith@…>, 7 years ago)

Patch with unit tests and docs

  • tests/modeltests/update_fields/models.py

     
     1""" 
     2#. Save only specific fields on update 
     3 
     4If a list of field names is given to the save() method, 
     5update only those in the database. 
     6""" 
     7from django.db import models 
     8 
     9class Article(models.Model): 
     10    headline = models.CharField(maxlength=100, default='Default headline') 
     11    body = models.TextField() 
     12    pub_date = models.DateTimeField() 
     13 
     14    class Meta: 
     15        ordering = ('pub_date','headline') 
     16 
     17    def __str__(self): 
     18        return self.headline 
     19 
     20__test__ = {'API_TESTS':""" 
     21# Create a couple of Articles. 
     22>>> from datetime import datetime 
     23>>> a = Article(headline='Article 1', body='Body 1', pub_date=datetime(2007, 5, 5)) 
     24>>> a.save() 
     25 
     26# Change headline and body but only save the headline 
     27>>> a.headline, a.body = 'Changed headline 1', 'Changed body 1' 
     28>>> a.save(['headline']) 
     29>>> a.headline 
     30'Changed headline 1' 
     31>>> a.body 
     32'Changed body 1' 
     33>>> a1 = Article.objects.get(pk=a.id) 
     34>>> a1.headline 
     35'Changed headline 1' 
     36>>> a1.body 
     37'Body 1' 
     38 
     39# Use the keyword argument form 
     40>>> a.headline, a.body = 'Changed headline 2nd time', 'Changed body 2nd time' 
     41>>> a.save(only_fields=['headline']) 
     42>>> a.headline 
     43'Changed headline 2nd time' 
     44>>> a.body 
     45'Changed body 2nd time' 
     46>>> a2 = Article.objects.get(pk=a.id) 
     47>>> a2.headline 
     48'Changed headline 2nd time' 
     49>>> a2.body 
     50'Body 1' 
     51"""} 
  • django/db/models/base.py

     
    9898        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 
    9999         
    100100        # There is a rather weird disparity here; if kwargs, it's set, then args 
    101         # overrides it. It should be one or the other; don't duplicate the work  
     101        # overrides it. It should be one or the other; don't duplicate the work. 
    102102        # The reason for the kwargs check is that standard iterator passes in by 
    103         # args, and nstantiation for iteration is 33% faster. 
     103        # args, and instantiation for iteration is 33% faster. 
    104104        args_len = len(args) 
    105105        if args_len > len(self._meta.fields): 
    106106            # Daft, but matches old exception sans the err msg. 
     
    198198 
    199199    _prepare = classmethod(_prepare) 
    200200 
    201     def save(self): 
     201    def save(self, only_fields=None): 
     202        "Save model object to database, creating if doesn't exist, otherwise updating" 
    202203        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 
    203204 
    204205        non_pks = [f for f in self._meta.fields if not f.primary_key] 
     206        if only_fields: 
     207            non_pks = [f for f in non_pks if f.name in only_fields] 
     208 
    205209        cursor = connection.cursor() 
    206210 
    207211        # First, try an UPDATE. If that doesn't update anything, do an INSERT. 
  • docs/db-api.txt

     
    134134 
    135135The ``save()`` method has no return value. 
    136136 
     137Specifying which fields to save 
     138------------------------------- 
     139 
     140If ``save()`` is passed a list of field names as its argument, only the fields 
     141named in that list will be saved to the database. This may be desirable if you 
     142want to update just one or a few fields on an object, as there will be a slight 
     143performance benefit from preventing all of the model fields from being updated 
     144in the database. For example: 
     145 
     146    b5.name = 'Changed name' 
     147    b5.save(['name'])   # Only 'name' is updated, no other fields in SQL 
     148 
     149Alternately, you can use the keyword argument ``only_fields`` to specify the 
     150list of field names: 
     151 
     152    b5.name = 'Name changed again' 
     153    b5.save(only_fields=['name']) 
     154 
    137155How Django knows to UPDATE vs. INSERT 
    138156------------------------------------- 
    139157