From d03b2de326a9d433d90aeab326f58d2d8e5262b2 Mon Sep 17 00:00:00 2001 From: Luke Plant Date: Mon, 6 Feb 2006 22:16:15 +0000 Subject: [PATCH] magic-removal: Fixed bug with m2m 'add()' in the case where the objects were already added (fixes one test) git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2285 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/fields/related.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index e5f38ae9db..f3e56a6aea 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -8,6 +8,10 @@ from django.core import validators from django import forms from django.dispatch import dispatcher +# For Python 2.3 +if not hasattr(__builtins__, 'set'): + from sets import Set as set + # Values for Relation.edit_inline. TABULAR, STACKED = 1, 2 @@ -114,13 +118,22 @@ def _add_m2m_items(rel_manager_inst, managerclass, rel_model, join_table, this_c for obj in objs: if not isinstance(obj, rel_model): raise ValueError, "positional arguments to add() must be %s instances" % rel_opts.object_name + # Add the newly created or already existing objects to the join table. - # TODO: Check to make sure the object isn't already in the join table. + # First find out which items are already added, to avoid adding them twice + new_ids = set([obj._get_pk_val() for obj in objs]) cursor = connection.cursor() - for obj in objs: + rowcount = cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \ + (rel_col_name, join_table, this_col_name, + rel_col_name, ",".join(['%s'] * len(new_ids))), + [this_pk_val] + list(new_ids)) + existing_ids = set([row[0] for row in cursor.fetchmany(rowcount)]) + + # Add the ones that aren't there already + for obj_id in (new_ids - existing_ids): cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \ (join_table, this_col_name, rel_col_name), - [this_pk_val, obj._get_pk_val()]) + [this_pk_val, obj_id]) connection.commit() def _remove_m2m_items(rel_model, join_table, this_col_name,