Ticket #4102: 4102-r16288.diff

File 4102-r16288.diff, 5.2 KB (added by ramiro, 4 years ago)

Patch updated to r16288, code was adapted to current code status and tests were converted to unit tests.

  • django/db/models/base.py

    diff --git a/django/db/models/base.py b/django/db/models/base.py
    a b  
    276276    _deferred = False
    277277
    278278    def __init__(self, *args, **kwargs):
     279        self._reset_modified_attrs()
    279280        signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
    280281
    281282        # Set up the storage for instance state
    282283        self._state = ModelState()
    283284
    284285        # There is a rather weird disparity here; if kwargs, it's set, then args
    285         # overrides it. It should be one or the other; don't duplicate the work
     286        # overrides it. It should be one or the other; don't duplicate the work.
    286287        # The reason for the kwargs check is that standard iterator passes in by
    287288        # args, and instantiation for iteration is 33% faster.
    288289        args_len = len(args)
     
    368369        super(Model, self).__init__()
    369370        signals.post_init.send(sender=self.__class__, instance=self)
    370371
     372    def __setattr__(self, name, value):
     373        if name not in self._modified_attrs:
     374            if not hasattr(self, name) or value != getattr(self, name):
     375                self._modified_attrs.append(name)
     376        super(Model, self).__setattr__(name, value)
     377
     378    def _reset_modified_attrs(self):
     379        self.__dict__['_modified_attrs'] = []
     380
    371381    def __repr__(self):
    372382        try:
    373383            u = unicode(self)
     
    514524        if not meta.proxy:
    515525            non_pks = [f for f in meta.local_fields if not f.primary_key]
    516526
     527            if self._state.db == using:
     528                modified_attrs = self._modified_attrs
     529                non_pks = [f for f in non_pks if (f.name in modified_attrs or f.attname in modified_attrs)]
     530                self._reset_modified_attrs()
     531
    517532            # First, try an UPDATE. If that doesn't update anything, do an INSERT.
    518533            pk_val = self._get_pk_val(meta)
    519534            pk_set = pk_val is not None
  • django/db/models/query.py

    diff --git a/django/db/models/query.py b/django/db/models/query.py
    a b  
    284284                else:
    285285                    # Omit aggregates in object creation.
    286286                    obj = model(*row[index_start:aggregate_start])
     287                    # Models keep a track of modified attrs to choose which
     288                    # fields to save. Since we're just pulling from the
     289                    # database, nothing has changed yet.
     290                    obj._reset_modified_attrs()
    287291
    288292                # Store the source database of the object
    289293                obj._state.db = db
  • new file tests/regressiontests/update_fields/models.py

    diff --git a/tests/regressiontests/update_fields/__init__.py b/tests/regressiontests/update_fields/__init__.py
    new file mode 100644
    diff --git a/tests/regressiontests/update_fields/models.py b/tests/regressiontests/update_fields/models.py
    new file mode 100644
    - +  
     1"""
     2Save only modified fields on update
     3"""
     4from django.db import models
     5
     6class Article(models.Model):
     7    headline = models.CharField(max_length=100, default='Default headline')
     8    body = models.TextField()
     9    pub_date = models.DateTimeField()
     10
     11    class Meta:
     12        ordering = ('pub_date','headline')
     13
     14    def __str__(self):
     15        return self.headline
  • new file tests/regressiontests/update_fields/tests.py

    diff --git a/tests/regressiontests/update_fields/tests.py b/tests/regressiontests/update_fields/tests.py
    new file mode 100644
    - +  
     1from datetime import datetime
     2
     3from django.test import TestCase
     4
     5from models import Article
     6
     7
     8class UpdateFieldsTest(TestCase):
     9
     10    def test_basic_update_fields(self):
     11        # Create a couple of Articles.
     12        a = Article(headline=u'Article 1', body=u'Body 1', pub_date=datetime(2007, 5, 5))
     13        a.save()
     14
     15        # Change headline and body on different instances, then save both to
     16        # verify that each only updated the modified field.
     17        a1 = Article.objects.get(pk=a.id)
     18        a2 = Article.objects.get(pk=a.id)
     19        a1.headline = u'Changed article 1'
     20        a2.body = u'Changed body 1'
     21        a1.save()
     22        a2.save()
     23        a3 = Article.objects.get(pk=a.id)
     24        self.assertEqual(a3.headline, u'Changed article 1')
     25        self.assertEqual(a3.body, u'Changed body 1')
     26
     27        # Fields entered at instantiation of a model which will already exists
     28        # should be saved as well.
     29        a = Article(id=a.id, headline=u'Reset article 1', body=u'Reset body 1', pub_date=datetime(2007, 5, 5))
     30        a.save()
     31        a3 = Article.objects.get(pk=a.id)
     32        self.assertEqual(a3.headline, u'Reset article 1')
     33        self.assertEqual(a3.body, u'Reset body 1')
     34
     35        # If the value doesn't change, it won't be marked as modified --
     36        # otherwise user input like forms/etc is going to mark everything
     37        # modified regardless.
     38        a1 = Article.objects.get(pk=a.id)
     39        a2 = Article.objects.get(pk=a.id)
     40        a1.headline = u'Changed article 2'
     41        a2.headline = a2.headline
     42        a2.body = u'Changed body 2'
     43        a1.save()
     44        a2.save()
     45        a3 = Article.objects.get(pk=a.id)
     46        self.assertEqual(a3.headline, u'Changed article 2')
     47        self.assertEqual(a3.body, u'Changed body 2')
Back to Top