Django

Code

Changeset 8267

Show
Ignore:
Timestamp:
08/09/08 12:19:23 (4 months ago)
Author:
mtredinnick
Message:

Added the ability to force an SQL insert (or force an update) via a model's
save() method.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/db/models/base.py

    r8244 r8267  
    1818from django.db.models.query import delete_objects, Q, CollectedObjects 
    1919from django.db.models.options import Options 
    20 from django.db import connection, transaction 
     20from django.db import connection, transaction, DatabaseError 
    2121from django.db.models import signals 
    2222from django.db.models.loading import register_models, get_model 
     
    269269    pk = property(_get_pk_val, _set_pk_val) 
    270270 
    271     def save(self): 
     271    def save(self, force_insert=False, force_update=False): 
    272272        """ 
    273273        Saves the current instance. Override this in a subclass if you want to 
    274274        control the saving process. 
    275         """ 
    276         self.save_base() 
     275 
     276        The 'force_insert' and 'force_update' parameters can be used to insist 
     277        that the "save" must be an SQL insert or update (or equivalent for 
     278        non-SQL backends), respectively. Normally, they should not be set. 
     279        """ 
     280        if force_insert and force_update: 
     281            raise ValueError("Cannot force both insert and updating in " 
     282                    "model saving.") 
     283        self.save_base(force_insert=force_insert, force_update=force_update) 
    277284 
    278285    save.alters_data = True 
    279286 
    280     def save_base(self, raw=False, cls=None): 
     287    def save_base(self, raw=False, cls=None, force_insert=False, 
     288            force_update=False): 
    281289        """ 
    282290        Does the heavy-lifting involved in saving. Subclasses shouldn't need to 
     
    285293        ('raw' and 'cls'). 
    286294        """ 
     295        assert not (force_insert and force_update) 
    287296        if not cls: 
    288297            cls = self.__class__ 
     
    320329        if pk_set: 
    321330            # Determine whether a record with the primary key already exists. 
    322             if manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by(): 
     331            if (force_update or (not force_insert and 
     332                    manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())): 
    323333                # It does already exist, so do an UPDATE. 
    324                 if non_pks: 
     334                if force_update or non_pks: 
    325335                    values = [(f, None, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks] 
    326                     manager.filter(pk=pk_val)._update(values) 
     336                    rows = manager.filter(pk=pk_val)._update(values) 
     337                    if force_update and not rows: 
     338                        raise DatabaseError("Forced update did not affect any rows.") 
    327339            else: 
    328340                record_exists = False 
    329341        if not pk_set or not record_exists: 
    330342            if not pk_set: 
     343                if force_update: 
     344                    raise ValueError("Cannot force an update in save() with no primary key.") 
    331345                values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)] 
    332346            else: 
  • django/trunk/django/db/models/query.py

    r8223 r8267  
    400400        query = self.query.clone(sql.UpdateQuery) 
    401401        query.add_update_values(kwargs) 
    402         query.execute_sql(None) 
     402        rows = query.execute_sql(None) 
    403403        transaction.commit_unless_managed() 
    404404        self._result_cache = None 
     405        return rows 
    405406    update.alters_data = True 
    406407 
     
    416417        query = self.query.clone(sql.UpdateQuery) 
    417418        query.add_update_fields(values) 
    418         query.execute_sql(None) 
    419419        self._result_cache = None 
     420        return query.execute_sql(None) 
    420421    _update.alters_data = True 
    421422 
  • django/trunk/django/db/models/sql/subqueries.py

    r7835 r8267  
    110110 
    111111    def execute_sql(self, result_type=None): 
    112         super(UpdateQuery, self).execute_sql(result_type) 
     112        """ 
     113        Execute the specified update. Returns the number of rows affected by 
     114        the primary update query (there could be other updates on related 
     115        tables, but their rowcounts are not returned). 
     116        """ 
     117        cursor = super(UpdateQuery, self).execute_sql(result_type) 
     118        rows = cursor.rowcount 
     119        del cursor 
    113120        for query in self.get_related_updates(): 
    114121            query.execute_sql(result_type) 
     122        return rows 
    115123 
    116124    def as_sql(self): 
  • django/trunk/docs/db-api.txt

    r8244 r8267  
    214214The one gotcha here is that you should be careful not to specify a primary-key 
    215215value explicitly when saving new objects, if you cannot guarantee the 
    216 primary-key value is unused. For more on this nuance, see 
    217 "Explicitly specifying auto-primary-key values" above. 
     216primary-key value is unused. For more on this nuance, see `Explicitly 
     217specifying auto-primary-key values`_ above and `Forcing an INSERT or UPDATE`_ 
     218below. 
     219 
     220Forcing an INSERT or UPDATE 
     221~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     222 
     223**New in Django development version** 
     224 
     225In some rare circumstances, it's necesary to be able to force the ``save()`` 
     226method to perform an SQL ``INSERT`` and not fall back to doing an ``UPDATE``. 
     227Or vice-versa: update, if possible, but not insert a new row. In these cases 
     228you can pass the ``force_insert=True`` or ``force_update=True`` parameters to 
     229the ``save()`` method. Passing both parameters is an error, since you cannot 
     230both insert *and* update at the same time. 
     231 
     232It should be very rare that you'll need to use these parameters. Django will 
     233almost always do the right thing and trying to override that will lead to 
     234errors that are difficult to track down. This feature is for advanced use 
     235only. 
    218236 
    219237Retrieving objects