Django

Code

Changeset 7043

Show
Ignore:
Timestamp:
01/28/08 08:27:53 (6 months ago)
Author:
mtredinnick
Message:

queryset-refactor: Added an update method to QuerySets?, since it's needed for
moving SQL out of the core code. Only direct fields and foreign keys can be
updated in this fashion, since multi-table updates are very non-portable.

This also cleans up the API for the UpdateQuery? class a bit. Still need to
change DeleteQuery? to work similarly, I suspect.

Refs #4260.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/queryset-refactor/django/db/models/query.py

    r7030 r7043  
    255255        self._result_cache = None 
    256256    delete.alters_data = True 
     257 
     258    def update(self, **kwargs): 
     259        """ 
     260        Updates all elements in the current QuerySet, setting all the given 
     261        fields to the appropriate values. 
     262        """ 
     263        query = self.query.clone(sql.UpdateQuery) 
     264        query.add_update_values(kwargs) 
     265        query.execute_sql(None) 
     266        self._result_cache=None 
     267    update.alters_Data = True 
    257268 
    258269    ################################################## 
  • django/branches/queryset-refactor/django/db/models/sql/query.py

    r7042 r7043  
    175175        obj.extra_order_by = self.extra_order_by[:] 
    176176        obj.__dict__.update(kwargs) 
     177        if hasattr(obj, '_setup_query'): 
     178            obj._setup_query() 
    177179        return obj 
    178180 
     
    11601162    def __init__(self, *args, **kwargs): 
    11611163        super(UpdateQuery, self).__init__(*args, **kwargs) 
     1164        self._setup_query() 
     1165 
     1166    def _setup_query(self): 
     1167        """ 
     1168        Run on initialisation and after cloning. 
     1169        """ 
    11621170        self.values = [] 
    11631171 
     
    11671175        parameters. 
    11681176        """ 
    1169         assert len(self.tables) == 1, \ 
    1170                 "Can only update one table at a time." 
     1177        self.select_related = False 
     1178        self.pre_sql_setup() 
     1179        if len(tables) != 1: 
     1180            raise TypeError('Updates can only access a single database table at a time.') 
    11711181        result = ['UPDATE %s' % self.tables[0]] 
    11721182        result.append('SET') 
    11731183        qn = self.quote_name_unless_alias 
    1174         values = ['%s = %s' % (qn(v[0]), v[1]) for v in self.values] 
     1184        values, update_params = [], [] 
     1185        for name, val in self.values: 
     1186            if val is not None: 
     1187                values.append('%s = %%s' % qn(name)) 
     1188                update_params.append(val) 
     1189            else: 
     1190                values.append('%s = NULL' % qn(name)) 
    11751191        result.append(', '.join(values)) 
    11761192        where, params = self.where.as_sql() 
    11771193        result.append('WHERE %s' % where) 
    1178         return ' '.join(result), tuple(params) 
    1179  
    1180     def do_query(self, table, values, where): 
    1181         self.tables = [table] 
    1182         self.values = values 
    1183         self.where = where 
    1184         self.execute_sql(NONE) 
     1194        return ' '.join(result), tuple(update_params + params) 
    11851195 
    11861196    def clear_related(self, related_field, pk_list): 
     
    11921202        """ 
    11931203        for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): 
    1194             where = self.where_class() 
     1204            self.where = self.where_class() 
    11951205            f = self.model._meta.pk 
    1196             where.add((None, f.column, f, 'in', 
     1206            self.where.add((None, f.column, f, 'in', 
    11971207                    pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), 
    11981208                    AND) 
    1199             values = [(related_field.column, 'NULL')] 
    1200             self.do_query(self.model._meta.db_table, values, where) 
     1209            self.values = [(related_field.column, None)] 
     1210            self.execute_sql(None) 
     1211 
     1212    def add_update_values(self, values): 
     1213        from django.db.models.base import Model 
     1214        for name, val in values.items(): 
     1215            field, direct, m2m = self.model._meta.get_field_by_name(name) 
     1216            if not direct or m2m: 
     1217                # Can only update non-relation fields and foreign keys. 
     1218                raise TypeError('Cannot update model field %r (only non-relations and foreign keys permitted).' % field) 
     1219            if field.rel and isinstance(val, Model): 
     1220                val = val.pk 
     1221            self.values.append((field.column, val)) 
    12011222 
    12021223class DateQuery(Query): 
  • django/branches/queryset-refactor/docs/db-api.txt

    r7042 r7043  
    19731973    Entry.objects.all().delete() 
    19741974 
     1975Updating multiple objects at once 
     1976================================= 
     1977 
     1978**New in Django development version** 
     1979 
     1980Sometimes you want to set a field to a particular value for all the objects in 
     1981a queryset. You can do this with the ``update()`` method. For example:: 
     1982 
     1983    # Update all the headlings to the same value. 
     1984    Entry.objects.all().update(headline='Everything is the same') 
     1985 
     1986You can only set non-relation fields and ``ForeignKey`` fields using this 
     1987method and the value you set the field to must be a normal Python value (you 
     1988can't set a field to be equal to some other field at the moment). 
     1989 
     1990To update ``ForeignKey`` fields, set the new value to be the new model 
     1991instance you want to point to. Example:: 
     1992 
     1993    b = Blog.objects.get(pk=1) 
     1994    # Make all entries belong to this blog. 
     1995    Entry.objects.all().update(blog=b) 
     1996 
     1997The ``update()`` method is applied instantly and doesn't return anything 
     1998(similar to ``delete()``). The only restriction on the queryset that is 
     1999updated is that it can only access one database table, the model's main 
     2000table. So don't try to filter based on related fields or anything like that; 
     2001it won't work. 
     2002 
    19752003Extra instance methods 
    19762004======================