Ticket #10109: patch_django_10109.20090123.diff
File patch_django_10109.20090123.diff, 14.3 KB (added by , 16 years ago) |
---|
-
django/db/models/sql/query.py
13 13 from django.utils.datastructures import SortedDict 14 14 from django.utils.encoding import force_unicode 15 15 from django.db.backends.util import truncate_name 16 from django.db import connection 16 from django.db import connection, transaction 17 17 from django.db.models import signals 18 18 from django.db.models.fields import FieldDoesNotExist 19 19 from django.db.models.query_utils import select_related_descend … … 1921 1921 select_col = join_info[RHS_JOIN_COL] 1922 1922 self.select = [(select_alias, select_col)] 1923 1923 1924 def _add_items(self, source_col_name, target_col_name, join_table, 1925 pk_val, instance, field, *objs): 1926 # join_table: name of the m2m link table 1927 # source_col_name: the PK colname in join_table for the source object 1928 # target_col_name: the PK colname in join_table for the target object 1929 # *objs - objects to add. Either object instances, or primary keys of object instances. 1930 1931 # If there aren't any objects, there is nothing to do. 1932 if objs: 1933 # Check that all the objects are of the right type 1934 new_ids = set() 1935 for obj in objs: 1936 if isinstance(obj, self.model): 1937 new_ids.add(obj._get_pk_val()) 1938 else: 1939 new_ids.add(obj) 1940 # Add the newly created or already existing objects to the join table. 1941 # First find out which items are already added, to avoid adding them twice 1942 cursor = connection.cursor() 1943 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \ 1944 (target_col_name, join_table, source_col_name, 1945 target_col_name, ",".join(['%s'] * len(new_ids))), 1946 [pk_val] + list(new_ids)) 1947 existing_ids = set([row[0] for row in cursor.fetchall()]) 1948 1949 # Add the ones that aren't there already 1950 for obj_id in (new_ids - existing_ids): 1951 cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \ 1952 (join_table, source_col_name, target_col_name), 1953 [pk_val, obj_id]) 1954 transaction.commit_unless_managed() 1955 1956 def _remove_items(self, source_col_name, target_col_name, join_table, 1957 pk_val, instance, field, *objs): 1958 # source_col_name: the PK colname in join_table for the source object 1959 # target_col_name: the PK colname in join_table for the target object 1960 # *objs - objects to remove 1961 1962 # If there aren't any objects, there is nothing to do. 1963 if objs: 1964 # Check that all the objects are of the right type 1965 old_ids = set() 1966 for obj in objs: 1967 if isinstance(obj, self.model): 1968 old_ids.add(obj._get_pk_val()) 1969 else: 1970 old_ids.add(obj) 1971 # Remove the specified objects from the join table 1972 cursor = connection.cursor() 1973 cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \ 1974 (join_table, source_col_name, 1975 target_col_name, ",".join(['%s'] * len(old_ids))), 1976 [pk_val] + list(old_ids)) 1977 transaction.commit_unless_managed() 1978 1979 def _clear_items(self, source_col_name, join_table, pk_val, instance, 1980 field): 1981 # source_col_name: the PK colname in join_table for the source object 1982 cursor = connection.cursor() 1983 cursor.execute("DELETE FROM %s WHERE %s = %%s" % \ 1984 (join_table, source_col_name), 1985 [pk_val]) 1986 transaction.commit_unless_managed() 1987 1924 1988 def execute_sql(self, result_type=MULTI): 1925 1989 """ 1926 1990 Run the query against the database and returns the result(s). The -
django/db/models/fields/related.py
1 from django.db import connection , transaction1 from django.db import connection 2 2 from django.db.backends import util 3 3 from django.db.models import signals, get_model 4 4 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist … … 361 361 and adds behavior for many-to-many related objects.""" 362 362 class ManyRelatedManager(superclass): 363 363 def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None, 364 join_table=None, source_col_name=None, target_col_name=None ):364 join_table=None, source_col_name=None, target_col_name=None, field=None): 365 365 super(ManyRelatedManager, self).__init__() 366 366 self.core_filters = core_filters 367 367 self.model = model … … 370 370 self.join_table = join_table 371 371 self.source_col_name = source_col_name 372 372 self.target_col_name = target_col_name 373 self.field = field 373 374 self.through = through 374 375 self._pk_val = self.instance._get_pk_val() 375 376 if self._pk_val is None: … … 382 383 # the add and remove methods do not exist. 383 384 if through is None: 384 385 def add(self, *objs): 385 self._add_items(self.source_col_name, self.target_col_name, *objs) 386 self.get_query_set()._add_items(self.source_col_name, 387 self.target_col_name, 388 self.join_table, 389 self._pk_val, 390 self.instance, 391 self.field, 392 *objs) 386 393 387 394 # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table 388 395 if self.symmetrical: 389 self._add_items(self.target_col_name, self.source_col_name, *objs) 396 self.get_query_set()._add_items(self.target_col_name, 397 self.source_col_name, 398 self.join_table, 399 self._pk_val, 400 self.instance, 401 self.field, 402 *objs) 390 403 add.alters_data = True 391 404 392 405 def remove(self, *objs): 393 self._remove_items(self.source_col_name, self.target_col_name, *objs) 406 self.get_query_set()._remove_items(self.source_col_name, 407 self.target_col_name, 408 self.join_table, 409 self._pk_val, 410 self.instance, 411 self.field, 412 *objs) 394 413 395 414 # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table 396 415 if self.symmetrical: 397 self._remove_items(self.target_col_name, self.source_col_name, *objs) 416 self.get_query_set()._remove_items(self.target_col_name, 417 self.source_col_name, 418 self.join_table, 419 self._pk_val, 420 self.instance, 421 self.field, 422 *objs) 398 423 remove.alters_data = True 399 424 400 425 def clear(self): 401 self._clear_items(self.source_col_name) 426 self.get_query_set()._clear_items(self.source_col_name, 427 self.join_table, 428 self._pk_val, 429 self.instance, 430 self.field) 402 431 403 432 # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table 404 433 if self.symmetrical: 405 self._clear_items(self.target_col_name) 434 self.get_query_set()._clear_items(self.target_col_name, 435 self.join_table, 436 self._pk_val, 437 self.instance, 438 self.field) 406 439 clear.alters_data = True 407 440 408 441 def create(self, **kwargs): … … 425 458 return obj, created 426 459 get_or_create.alters_data = True 427 460 428 def _add_items(self, source_col_name, target_col_name, *objs):429 # join_table: name of the m2m link table430 # source_col_name: the PK colname in join_table for the source object431 # target_col_name: the PK colname in join_table for the target object432 # *objs - objects to add. Either object instances, or primary keys of object instances.433 434 # If there aren't any objects, there is nothing to do.435 if objs:436 # Check that all the objects are of the right type437 new_ids = set()438 for obj in objs:439 if isinstance(obj, self.model):440 new_ids.add(obj._get_pk_val())441 else:442 new_ids.add(obj)443 # Add the newly created or already existing objects to the join table.444 # First find out which items are already added, to avoid adding them twice445 cursor = connection.cursor()446 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \447 (target_col_name, self.join_table, source_col_name,448 target_col_name, ",".join(['%s'] * len(new_ids))),449 [self._pk_val] + list(new_ids))450 existing_ids = set([row[0] for row in cursor.fetchall()])451 452 # Add the ones that aren't there already453 for obj_id in (new_ids - existing_ids):454 cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \455 (self.join_table, source_col_name, target_col_name),456 [self._pk_val, obj_id])457 transaction.commit_unless_managed()458 459 def _remove_items(self, source_col_name, target_col_name, *objs):460 # source_col_name: the PK colname in join_table for the source object461 # target_col_name: the PK colname in join_table for the target object462 # *objs - objects to remove463 464 # If there aren't any objects, there is nothing to do.465 if objs:466 # Check that all the objects are of the right type467 old_ids = set()468 for obj in objs:469 if isinstance(obj, self.model):470 old_ids.add(obj._get_pk_val())471 else:472 old_ids.add(obj)473 # Remove the specified objects from the join table474 cursor = connection.cursor()475 cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \476 (self.join_table, source_col_name,477 target_col_name, ",".join(['%s'] * len(old_ids))),478 [self._pk_val] + list(old_ids))479 transaction.commit_unless_managed()480 481 def _clear_items(self, source_col_name):482 # source_col_name: the PK colname in join_table for the source object483 cursor = connection.cursor()484 cursor.execute("DELETE FROM %s WHERE %s = %%s" % \485 (self.join_table, source_col_name),486 [self._pk_val])487 transaction.commit_unless_managed()488 489 461 return ManyRelatedManager 490 462 491 463 class ManyRelatedObjectsDescriptor(object): … … 561 533 symmetrical=(self.field.rel.symmetrical and instance.__class__ == rel_model), 562 534 join_table=qn(self.field.m2m_db_table()), 563 535 source_col_name=qn(self.field.m2m_column_name()), 564 target_col_name=qn(self.field.m2m_reverse_name()) 536 target_col_name=qn(self.field.m2m_reverse_name()), 537 field=self.field 565 538 ) 566 539 567 540 return manager -
django/db/models/query.py
710 710 obj = self.values("pk") 711 711 return obj.query.as_nested_sql() 712 712 713 ################################################ 714 # PRIVATE METHODS THAT DEAL WITH M2M RELATIONS # 715 ################################################ 716 717 def _add_items(self, source_col_name=None, target_col_name=None, 718 join_table=None, pk_val=None, 719 instance=None, field=None, *objs): 720 self.query._add_items(source_col_name, target_col_name, 721 join_table, pk_val,instance, field, *objs) 722 723 def _remove_items(self, source_col_name=None, target_col_name=None, 724 join_table=None, pk_val=None, 725 instance=None, field=None, *objs): 726 self.query._remove_items(source_col_name, target_col_name, 727 join_table, pk_val, instance, field, *objs) 728 729 def _clear_items(self, source_col_name=None, join_table=None, pk_val=None, 730 instance=None, field=None): 731 self.query._clear_items(source_col_name, join_table, pk_val, instance, 732 field) 733 713 734 # When used as part of a nested query, a queryset will never be an "always 714 735 # empty" result. 715 736 value_annotation = True