Ticket #10109: patch_django_10109.20090422.diff
File patch_django_10109.20090422.diff, 14.7 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 … … 2284 2284 self.select = [(select_alias, select_col)] 2285 2285 self.remove_inherited_models() 2286 2286 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 2287 2354 def execute_sql(self, result_type=MULTI): 2288 2355 """ 2289 2356 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 … … 382 382 and adds behavior for many-to-many related objects.""" 383 383 class ManyRelatedManager(superclass): 384 384 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): 386 386 super(ManyRelatedManager, self).__init__() 387 387 self.core_filters = core_filters 388 388 self.model = model … … 391 391 self.join_table = join_table 392 392 self.source_col_name = source_col_name 393 393 self.target_col_name = target_col_name 394 self.field = field 394 395 self.through = through 395 396 self._pk_val = self.instance._get_pk_val() 396 397 if self._pk_val is None: … … 403 404 # the add and remove methods do not exist. 404 405 if through is None: 405 406 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) 407 414 408 415 # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table 409 416 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) 411 424 add.alters_data = True 412 425 413 426 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) 415 434 416 435 # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table 417 436 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) 419 444 remove.alters_data = True 420 445 421 446 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) 423 452 424 453 # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table 425 454 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) 427 460 clear.alters_data = True 428 461 429 462 def create(self, **kwargs): … … 446 479 return obj, created 447 480 get_or_create.alters_data = True 448 481 449 def _add_items(self, source_col_name, target_col_name, *objs):450 # join_table: name of the m2m link table451 # source_col_name: the PK colname in join_table for the source object452 # target_col_name: the PK colname in join_table for the target object453 # *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 Model458 # Check that all the objects are of the right type459 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_name465 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 twice469 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 already477 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 object485 # target_col_name: the PK colname in join_table for the target object486 # *objs - objects to remove487 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 type491 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 table498 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 object507 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 513 482 return ManyRelatedManager 514 483 515 484 class ManyRelatedObjectsDescriptor(object): … … 585 554 symmetrical=(self.field.rel.symmetrical and isinstance(instance, rel_model)), 586 555 join_table=qn(self.field.m2m_db_table()), 587 556 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 589 559 ) 590 560 591 561 return manager -
django/db/models/query.py
683 683 obj = self.values("pk") 684 684 return obj.query.as_nested_sql() 685 685 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 686 707 # When used as part of a nested query, a queryset will never be an "always 687 708 # empty" result. 688 709 value_annotation = True