Django

Code

Ticket #4102: 4102-dirty.4.patch

File 4102-dirty.4.patch, 4.9 kB (added by Collin Grady <cgrady@the-magi.us>, 1 year ago)
  • django/db/models/base.py

    old new  
    9494    def __ne__(self, other): 
    9595        return not self.__eq__(other) 
    9696 
     97    _dirty = {} 
     98 
     99    def __setattr__(self, name, value): 
     100        if name != '_dirty' and (not hasattr(self, name) or value != getattr(self, name)): 
     101            self._dirty[name] = True 
     102        super(Model, self).__setattr__(name, value) 
     103 
     104    def _wash(self): 
     105        self._dirty = {} 
     106 
    97107    def __init__(self, *args, **kwargs): 
    98108        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 
    99109 
     110        wash = kwargs.pop('wash', False) 
     111        dirty = {} 
     112 
    100113        # 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 
     114        # overrides it. It should be one or the other; don't duplicate the work. 
    102115        # The reason for the kwargs check is that standard iterator passes in by 
    103         # args, and nstantiation for iteration is 33% faster. 
     116        # args, and instantiation for iteration is 33% faster. 
    104117        args_len = len(args) 
    105118        if args_len > len(self._meta.fields): 
    106119            # Daft, but matches old exception sans the err msg. 
     
    114127            # without changing the logic. 
    115128            for val, field in izip(args, fields_iter): 
    116129                setattr(self, field.attname, val) 
     130                dirty[field.attname] = True 
    117131        else: 
    118132            # Slower, kwargs-ready version. 
    119133            for val, field in izip(args, fields_iter): 
    120134                setattr(self, field.attname, val) 
     135                dirty[field.attname] = True 
    121136                kwargs.pop(field.name, None) 
    122137                # Maintain compatibility with existing calls. 
    123138                if isinstance(field.rel, ManyToOneRel): 
     
    164179                    pass 
    165180            if kwargs: 
    166181                raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 
     182 
     183        self._wash() 
     184        if not wash: 
     185            self._dirty = dirty 
    167186        dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) 
    168187 
    169188    def add_to_class(cls, name, value): 
     
    199218    _prepare = classmethod(_prepare) 
    200219 
    201220    def save(self): 
     221        "Save model object to database, creating if doesn't exist, otherwise updating" 
    202222        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 
    203223 
    204         non_pks = [f for f in self._meta.fields if not f.primary_key] 
     224        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))] 
     225        self._wash() 
    205226        cursor = connection.cursor() 
    206227 
    207228        # First, try an UPDATE. If that doesn't update anything, do an INSERT. 
  • django/db/models/query.py

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

    old new  
     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"""}