Ticket #4102: 4102-dirty.5.patch

File 4102-dirty.5.patch, 9.3 KB (added by Collin Grady <cgrady@…>, 17 years ago)

Updated patch against [5832], fixed bug with kwargs instantiation and dirty flags

  • django/db/models/base.py

     
    9797    def __ne__(self, other):
    9898        return not self.__eq__(other)
    9999
     100    _dirty = {}
     101
     102    def __setattr__(self, name, value):
     103        if name != '_dirty' and (not hasattr(self, name) or value != getattr(self, name)):
     104            self._dirty[name] = True
     105        super(Model, self).__setattr__(name, value)
     106
     107    def _wash(self):
     108        self._dirty = {}
     109
    100110    def __init__(self, *args, **kwargs):
    101111        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
    102112
     113        wash = kwargs.pop('wash', False)
     114        dirty = {}
     115
    103116        # There is a rather weird disparity here; if kwargs, it's set, then args
    104         # overrides it. It should be one or the other; don't duplicate the work
     117        # overrides it. It should be one or the other; don't duplicate the work.
    105118        # The reason for the kwargs check is that standard iterator passes in by
    106         # args, and nstantiation for iteration is 33% faster.
     119        # args, and instantiation for iteration is 33% faster.
    107120        args_len = len(args)
    108121        if args_len > len(self._meta.fields):
    109122            # Daft, but matches old exception sans the err msg.
     
    117130            # without changing the logic.
    118131            for val, field in izip(args, fields_iter):
    119132                setattr(self, field.attname, val)
     133                print field.attname, val
     134                dirty[field.attname] = True
    120135        else:
    121136            # Slower, kwargs-ready version.
    122137            for val, field in izip(args, fields_iter):
    123138                setattr(self, field.attname, val)
     139                print field.attname, val
     140                dirty[field.attname] = True
    124141                kwargs.pop(field.name, None)
    125142                # Maintain compatibility with existing calls.
    126143                if isinstance(field.rel, ManyToOneRel):
     
    130147        # keywords, or default.
    131148
    132149        for field in fields_iter:
     150            if field.attname in kwargs:
     151                dirty[field.attname] = True
    133152            if kwargs:
    134153                if isinstance(field.rel, ManyToOneRel):
    135154                    try:
     
    167186                    pass
    168187            if kwargs:
    169188                raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
     189
     190        self._wash()
     191        if not wash:
     192            self._dirty = dirty
    170193        dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self)
    171194
    172195    def add_to_class(cls, name, value):
     
    202225    _prepare = classmethod(_prepare)
    203226
    204227    def save(self, raw=False):
     228        "Save model object to database, creating if doesn't exist, otherwise updating"
    205229        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
    206230
    207         non_pks = [f for f in self._meta.fields if not f.primary_key]
     231        non_pks = [f for f in self._meta.fields if not f.primary_key and (self._dirty.get(f.name, False) or self._dirty.get(f.attname, False))]
     232        self._wash()
    208233        cursor = connection.cursor()
    209234
    210235        # First, try an UPDATE. If that doesn't update anything, do an INSERT.
  • django/db/models/query.py

     
    202202                    obj, index_end = get_cached_row(klass=self.model, row=row,
    203203                                                    index_start=0, max_depth=self._max_related_depth)
    204204                else:
    205                     obj = self.model(*row[:index_end])
     205                    obj = self.model(wash=True, *row[:index_end])
    206206                for i, k in enumerate(extra_select):
    207207                    setattr(obj, k[0], row[index_end+i])
    208208                yield obj
  • tests/modeltests/update_fields/models.py

     
     1"""
     2#. Save only modified fields on update
     3"""
     4from django.db import models
     5
     6class Article(models.Model):
     7    headline = models.CharField(maxlength=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
     16
     17__test__ = {'API_TESTS':"""
     18# Create a couple of Articles.
     19>>> from datetime import datetime
     20>>> a = Article(headline='Article 1', body='Body 1', pub_date=datetime(2007, 5, 5))
     21>>> a.save()
     22
     23# Change headline and body on different instances, then save both to verify
     24# that each only updated the modified field
     25>>> a1 = Article.objects.get(pk=a.id)
     26>>> a2 = Article.objects.get(pk=a.id)
     27>>> a1.headline = 'Changed article 1'
     28>>> a2.body = 'Changed body 1'
     29>>> a1.save()
     30>>> a2.save()
     31>>> a3 = Article.objects.get(pk=a.id)
     32>>> a3.headline
     33'Changed article 1'
     34>>> a3.body
     35'Changed body 1'
     36"""}
     37"""
     38#. Save only modified fields on update
     39"""
     40from django.db import models
     41
     42class Article(models.Model):
     43    headline = models.CharField(maxlength=100, default='Default headline')
     44    body = models.TextField()
     45    pub_date = models.DateTimeField()
     46
     47    class Meta:
     48        ordering = ('pub_date','headline')
     49
     50    def __str__(self):
     51        return self.headline
     52
     53__test__ = {'API_TESTS':"""
     54# Create a couple of Articles.
     55>>> from datetime import datetime
     56>>> a = Article(headline='Article 1', body='Body 1', pub_date=datetime(2007, 5, 5))
     57>>> a.save()
     58
     59# Change headline and body on different instances, then save both to verify
     60# that each only updated the modified field
     61>>> a1 = Article.objects.get(pk=a.id)
     62>>> a2 = Article.objects.get(pk=a.id)
     63>>> a1.headline = 'Changed article 1'
     64>>> a2.body = 'Changed body 1'
     65>>> a1.save()
     66>>> a2.save()
     67>>> a3 = Article.objects.get(pk=a.id)
     68>>> a3.headline
     69'Changed article 1'
     70>>> a3.body
     71'Changed body 1'
     72"""}
     73"""
     74#. Save only modified fields on update
     75"""
     76from django.db import models
     77
     78class Article(models.Model):
     79    headline = models.CharField(maxlength=100, default='Default headline')
     80    body = models.TextField()
     81    pub_date = models.DateTimeField()
     82
     83    class Meta:
     84        ordering = ('pub_date','headline')
     85
     86    def __str__(self):
     87        return self.headline
     88
     89__test__ = {'API_TESTS':"""
     90# Create a couple of Articles.
     91>>> from datetime import datetime
     92>>> a = Article(headline='Article 1', body='Body 1', pub_date=datetime(2007, 5, 5))
     93>>> a.save()
     94
     95# Change headline and body on different instances, then save both to verify
     96# that each only updated the modified field
     97>>> a1 = Article.objects.get(pk=a.id)
     98>>> a2 = Article.objects.get(pk=a.id)
     99>>> a1.headline = 'Changed article 1'
     100>>> a2.body = 'Changed body 1'
     101>>> a1.save()
     102>>> a2.save()
     103>>> a3 = Article.objects.get(pk=a.id)
     104>>> a3.headline
     105'Changed article 1'
     106>>> a3.body
     107'Changed body 1'
     108"""}
     109"""
     110#. Save only modified fields on update
     111"""
     112from django.db import models
     113
     114class Article(models.Model):
     115    headline = models.CharField(maxlength=100, default='Default headline')
     116    body = models.TextField()
     117    pub_date = models.DateTimeField()
     118
     119    class Meta:
     120        ordering = ('pub_date','headline')
     121
     122    def __str__(self):
     123        return self.headline
     124
     125__test__ = {'API_TESTS':"""
     126# Create a couple of Articles.
     127>>> from datetime import datetime
     128>>> a = Article(headline='Article 1', body='Body 1', pub_date=datetime(2007, 5, 5))
     129>>> a.save()
     130
     131# Change headline and body on different instances, then save both to verify
     132# that each only updated the modified field
     133>>> a1 = Article.objects.get(pk=a.id)
     134>>> a2 = Article.objects.get(pk=a.id)
     135>>> a1.headline = 'Changed article 1'
     136>>> a2.body = 'Changed body 1'
     137>>> a1.save()
     138>>> a2.save()
     139>>> a3 = Article.objects.get(pk=a.id)
     140>>> a3.headline
     141'Changed article 1'
     142>>> a3.body
     143'Changed body 1'
     144"""}
     145"""
     146#. Save only modified fields on update
     147"""
     148from django.db import models
     149
     150class Article(models.Model):
     151    headline = models.CharField(maxlength=100, default='Default headline')
     152    body = models.TextField()
     153    pub_date = models.DateTimeField()
     154
     155    class Meta:
     156        ordering = ('pub_date','headline')
     157
     158    def __str__(self):
     159        return self.headline
     160
     161__test__ = {'API_TESTS':"""
     162# Create a couple of Articles.
     163>>> from datetime import datetime
     164>>> a = Article(headline='Article 1', body='Body 1', pub_date=datetime(2007, 5, 5))
     165>>> a.save()
     166
     167# Change headline and body on different instances, then save both to verify
     168# that each only updated the modified field
     169>>> a1 = Article.objects.get(pk=a.id)
     170>>> a2 = Article.objects.get(pk=a.id)
     171>>> a1.headline = 'Changed article 1'
     172>>> a2.body = 'Changed body 1'
     173>>> a1.save()
     174>>> a2.save()
     175>>> a3 = Article.objects.get(pk=a.id)
     176>>> a3.headline
     177'Changed article 1'
     178>>> a3.body
     179'Changed body 1'
     180"""}
Back to Top