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

File 4102-only-udpate-fields.patch, 4.1 KB (added by Paul Smith <paulsmith@…>, 8 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
Back to Top