Fixed #3389 -- Many-to-many sets can now be assigned with primary key values

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4448 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-01-29 16:09:25 +00:00
parent a031cadf4e
commit d28a63cc00
2 changed files with 24 additions and 8 deletions

View File

@ -316,18 +316,20 @@ def create_many_related_manager(superclass):
# join_table: name of the m2m link table # join_table: name of the m2m link table
# source_col_name: the PK colname in join_table for the source object # source_col_name: the PK colname in join_table for the source object
# target_col_name: the PK colname in join_table for the target object # target_col_name: the PK colname in join_table for the target object
# *objs - objects to add # *objs - objects to add. Either object instances, or primary keys of object instances.
from django.db import connection from django.db import connection
# If there aren't any objects, there is nothing to do. # If there aren't any objects, there is nothing to do.
if objs: if objs:
# Check that all the objects are of the right type # Check that all the objects are of the right type
new_ids = set()
for obj in objs: for obj in objs:
if not isinstance(obj, self.model): if isinstance(obj, self.model):
raise ValueError, "objects to add() must be %s instances" % self.model._meta.object_name new_ids.add(obj._get_pk_val())
else:
new_ids.add(obj)
# Add the newly created or already existing objects to the join table. # Add the newly created or already existing objects to the join table.
# First find out which items are already added, to avoid adding them twice # 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() cursor = connection.cursor()
cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \ cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
(target_col_name, self.join_table, source_col_name, (target_col_name, self.join_table, source_col_name,
@ -354,11 +356,13 @@ def create_many_related_manager(superclass):
# If there aren't any objects, there is nothing to do. # If there aren't any objects, there is nothing to do.
if objs: if objs:
# Check that all the objects are of the right type # Check that all the objects are of the right type
old_ids = set()
for obj in objs: for obj in objs:
if not isinstance(obj, self.model): if isinstance(obj, self.model):
raise ValueError, "objects to remove() must be %s instances" % self.model._meta.object_name old_ids.add(obj._get_pk_val())
else:
old_ids.add(obj)
# Remove the specified objects from the join table # Remove the specified objects from the join table
old_ids = set([obj._get_pk_val() for obj in objs])
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \ cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
(self.join_table, source_col_name, (self.join_table, source_col_name,

View File

@ -203,7 +203,19 @@ __test__ = {'API_TESTS':"""
>>> p2.article_set.all() >>> p2.article_set.all()
[<Article: Oxygen-free diet works wonders>] [<Article: Oxygen-free diet works wonders>]
# Recreate the article and Publication we just deleted. # Relation sets can also be set using primary key values
>>> p2.article_set = [a4.id, a5.id]
>>> p2.article_set.all()
[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>]
>>> a4.publications.all()
[<Publication: Science News>]
>>> a4.publications = [p3.id]
>>> p2.article_set.all()
[<Article: Oxygen-free diet works wonders>]
>>> a4.publications.all()
[<Publication: Science Weekly>]
# Recreate the article and Publication we have deleted.
>>> p1 = Publication(id=None, title='The Python Journal') >>> p1 = Publication(id=None, title='The Python Journal')
>>> p1.save() >>> p1.save()
>>> a2 = Article(id=None, headline='NASA uses Python') >>> a2 = Article(id=None, headline='NASA uses Python')