Ticket #10109: patch_django_10109.20090422.diff

File patch_django_10109.20090422.diff, 14.7 KB (added by David Larlet, 9 years ago)

Update patch against r10618

  • django/db/models/sql/query.py

     
    1313from django.utils.datastructures import SortedDict
    1414from django.utils.encoding import force_unicode
    1515from django.db.backends.util import truncate_name
    16 from django.db import connection
     16from django.db import connection, transaction
    1717from django.db.models import signals
    1818from django.db.models.fields import FieldDoesNotExist
    1919from django.db.models.query_utils import select_related_descend
     
    22842284        self.select = [(select_alias, select_col)]
    22852285        self.remove_inherited_models()
    22862286
     2287    def _add_items(self, source_col_name, target_col_name, join_table,
     2288                   pk_val, instance, field, *objs):
     2289        # join_table: name of the m2m link table
     2290        # source_col_name: the PK colname in join_table for the source object
     2291        # target_col_name: the PK colname in join_table for the target object
     2292        # *objs - objects to add. Either object instances, or primary keys of object instances.
     2293       
     2294        # If there aren't any objects, there is nothing to do.
     2295        if objs:
     2296            from django.db.models.base import Model
     2297            # Check that all the objects are of the right type
     2298            new_ids = set()
     2299            for obj in objs:
     2300                if isinstance(obj, self.model):
     2301                    new_ids.add(obj._get_pk_val())
     2302                elif isinstance(obj, Model):
     2303                    raise TypeError, "'%s' instance expected" % self.model._meta.object_name
     2304                else:
     2305                    new_ids.add(obj)
     2306            # Add the newly created or already existing objects to the join table.
     2307            # First find out which items are already added, to avoid adding them twice
     2308            cursor = connection.cursor()
     2309            cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
     2310                (target_col_name, join_table, source_col_name,
     2311                target_col_name, ",".join(['%s'] * len(new_ids))),
     2312                [pk_val] + list(new_ids))
     2313            existing_ids = set([row[0] for row in cursor.fetchall()])
     2314       
     2315            # Add the ones that aren't there already
     2316            for obj_id in (new_ids - existing_ids):
     2317                cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
     2318                    (join_table, source_col_name, target_col_name),
     2319                    [pk_val, obj_id])
     2320            transaction.commit_unless_managed()
     2321
     2322    def _remove_items(self, source_col_name, target_col_name, join_table,
     2323                      pk_val, instance, field, *objs):
     2324        # source_col_name: the PK colname in join_table for the source object
     2325        # target_col_name: the PK colname in join_table for the target object
     2326        # *objs - objects to remove
     2327       
     2328        # If there aren't any objects, there is nothing to do.
     2329        if objs:
     2330            # Check that all the objects are of the right type
     2331            old_ids = set()
     2332            for obj in objs:
     2333                if isinstance(obj, self.model):
     2334                    old_ids.add(obj._get_pk_val())
     2335                else:
     2336                    old_ids.add(obj)
     2337            # Remove the specified objects from the join table
     2338            cursor = connection.cursor()
     2339            cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
     2340                (join_table, source_col_name,
     2341                target_col_name, ",".join(['%s'] * len(old_ids))),
     2342                [pk_val] + list(old_ids))
     2343            transaction.commit_unless_managed()
     2344   
     2345    def _clear_items(self, source_col_name, join_table, pk_val, instance,
     2346                     field):
     2347        # source_col_name: the PK colname in join_table for the source object
     2348        cursor = connection.cursor()
     2349        cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
     2350            (join_table, source_col_name),
     2351            [pk_val])
     2352        transaction.commit_unless_managed()
     2353
    22872354    def execute_sql(self, result_type=MULTI):
    22882355        """
    22892356        Run the query against the database and returns the result(s). The
  • django/db/models/fields/related.py

     
    1 from django.db import connection, transaction
     1from django.db import connection
    22from django.db.backends import util
    33from django.db.models import signals, get_model
    44from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist
     
    382382    and adds behavior for many-to-many related objects."""
    383383    class ManyRelatedManager(superclass):
    384384        def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
    385                 join_table=None, source_col_name=None, target_col_name=None):
     385                join_table=None, source_col_name=None, target_col_name=None, field=None):
    386386            super(ManyRelatedManager, self).__init__()
    387387            self.core_filters = core_filters
    388388            self.model = model
     
    391391            self.join_table = join_table
    392392            self.source_col_name = source_col_name
    393393            self.target_col_name = target_col_name
     394            self.field = field
    394395            self.through = through
    395396            self._pk_val = self.instance._get_pk_val()
    396397            if self._pk_val is None:
     
    403404        # the add and remove methods do not exist.
    404405        if through is None:
    405406            def add(self, *objs):
    406                 self._add_items(self.source_col_name, self.target_col_name, *objs)
     407                self.get_query_set()._add_items(self.source_col_name,
     408                                                self.target_col_name,
     409                                                self.join_table,
     410                                                self._pk_val,
     411                                                self.instance,
     412                                                self.field,
     413                                                *objs)
    407414
    408415                # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
    409416                if self.symmetrical:
    410                     self._add_items(self.target_col_name, self.source_col_name, *objs)
     417                    self.get_query_set()._add_items(self.target_col_name,
     418                                                    self.source_col_name,
     419                                                    self.join_table,
     420                                                    self._pk_val,
     421                                                    self.instance,
     422                                                    self.field,
     423                                                    *objs)
    411424            add.alters_data = True
    412425
    413426            def remove(self, *objs):
    414                 self._remove_items(self.source_col_name, self.target_col_name, *objs)
     427                self.get_query_set()._remove_items(self.source_col_name,
     428                                                   self.target_col_name,
     429                                                   self.join_table,
     430                                                   self._pk_val,
     431                                                   self.instance,
     432                                                   self.field,
     433                                                   *objs)
    415434
    416435                # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table
    417436                if self.symmetrical:
    418                     self._remove_items(self.target_col_name, self.source_col_name, *objs)
     437                    self.get_query_set()._remove_items(self.target_col_name,
     438                                                       self.source_col_name,
     439                                                       self.join_table,
     440                                                       self._pk_val,
     441                                                       self.instance,
     442                                                       self.field,
     443                                                       *objs)
    419444            remove.alters_data = True
    420445
    421446        def clear(self):
    422             self._clear_items(self.source_col_name)
     447            self.get_query_set()._clear_items(self.source_col_name,
     448                                              self.join_table,
     449                                              self._pk_val,
     450                                              self.instance,
     451                                              self.field)
    423452
    424453            # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table
    425454            if self.symmetrical:
    426                 self._clear_items(self.target_col_name)
     455                self.get_query_set()._clear_items(self.target_col_name,
     456                                                  self.join_table,
     457                                                  self._pk_val,
     458                                                  self.instance,
     459                                                  self.field)
    427460        clear.alters_data = True
    428461
    429462        def create(self, **kwargs):
     
    446479            return obj, created
    447480        get_or_create.alters_data = True
    448481
    449         def _add_items(self, source_col_name, target_col_name, *objs):
    450             # join_table: name of the m2m link table
    451             # source_col_name: the PK colname in join_table for the source object
    452             # target_col_name: the PK colname in join_table for the target object
    453             # *objs - objects to add. Either object instances, or primary keys of object instances.
    454 
    455             # If there aren't any objects, there is nothing to do.
    456             if objs:
    457                 from django.db.models.base import Model
    458                 # Check that all the objects are of the right type
    459                 new_ids = set()
    460                 for obj in objs:
    461                     if isinstance(obj, self.model):
    462                         new_ids.add(obj._get_pk_val())
    463                     elif isinstance(obj, Model):
    464                         raise TypeError, "'%s' instance expected" % self.model._meta.object_name
    465                     else:
    466                         new_ids.add(obj)
    467                 # Add the newly created or already existing objects to the join table.
    468                 # First find out which items are already added, to avoid adding them twice
    469                 cursor = connection.cursor()
    470                 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
    471                     (target_col_name, self.join_table, source_col_name,
    472                     target_col_name, ",".join(['%s'] * len(new_ids))),
    473                     [self._pk_val] + list(new_ids))
    474                 existing_ids = set([row[0] for row in cursor.fetchall()])
    475 
    476                 # Add the ones that aren't there already
    477                 for obj_id in (new_ids - existing_ids):
    478                     cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
    479                         (self.join_table, source_col_name, target_col_name),
    480                         [self._pk_val, obj_id])
    481                 transaction.commit_unless_managed()
    482 
    483         def _remove_items(self, source_col_name, target_col_name, *objs):
    484             # source_col_name: the PK colname in join_table for the source object
    485             # target_col_name: the PK colname in join_table for the target object
    486             # *objs - objects to remove
    487 
    488             # If there aren't any objects, there is nothing to do.
    489             if objs:
    490                 # Check that all the objects are of the right type
    491                 old_ids = set()
    492                 for obj in objs:
    493                     if isinstance(obj, self.model):
    494                         old_ids.add(obj._get_pk_val())
    495                     else:
    496                         old_ids.add(obj)
    497                 # Remove the specified objects from the join table
    498                 cursor = connection.cursor()
    499                 cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
    500                     (self.join_table, source_col_name,
    501                     target_col_name, ",".join(['%s'] * len(old_ids))),
    502                     [self._pk_val] + list(old_ids))
    503                 transaction.commit_unless_managed()
    504 
    505         def _clear_items(self, source_col_name):
    506             # source_col_name: the PK colname in join_table for the source object
    507             cursor = connection.cursor()
    508             cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
    509                 (self.join_table, source_col_name),
    510                 [self._pk_val])
    511             transaction.commit_unless_managed()
    512 
    513482    return ManyRelatedManager
    514483
    515484class ManyRelatedObjectsDescriptor(object):
     
    585554            symmetrical=(self.field.rel.symmetrical and isinstance(instance, rel_model)),
    586555            join_table=qn(self.field.m2m_db_table()),
    587556            source_col_name=qn(self.field.m2m_column_name()),
    588             target_col_name=qn(self.field.m2m_reverse_name())
     557            target_col_name=qn(self.field.m2m_reverse_name()),
     558            field=self.field
    589559        )
    590560
    591561        return manager
  • django/db/models/query.py

     
    683683        obj = self.values("pk")
    684684        return obj.query.as_nested_sql()
    685685
     686    ################################################
     687    # PRIVATE METHODS THAT DEAL WITH M2M RELATIONS #
     688    ################################################
     689   
     690    def _add_items(self, source_col_name=None, target_col_name=None,
     691                   join_table=None, pk_val=None,
     692                   instance=None, field=None, *objs):
     693        self.query._add_items(source_col_name, target_col_name,
     694                              join_table, pk_val,instance, field, *objs)
     695
     696    def _remove_items(self, source_col_name=None, target_col_name=None,
     697                      join_table=None, pk_val=None,
     698                      instance=None, field=None, *objs):
     699        self.query._remove_items(source_col_name, target_col_name,
     700                                 join_table, pk_val, instance, field, *objs)
     701
     702    def _clear_items(self, source_col_name=None, join_table=None, pk_val=None,
     703                     instance=None, field=None):
     704        self.query._clear_items(source_col_name, join_table, pk_val, instance,
     705                                field)
     706
    686707    # When used as part of a nested query, a queryset will never be an "always
    687708    # empty" result.
    688709    value_annotation = True
Back to Top