Code

Ticket #3389: m2m_ids.diff

File m2m_ids.diff, 3.5 KB (added by russellm, 7 years ago)

Patch to allow m2m relations to be set by assigning primary key

Line 
1Index: django/db/models/fields/related.py
2===================================================================
3--- django/db/models/fields/related.py  (revision 4429)
4+++ django/db/models/fields/related.py  (working copy)
5@@ -316,18 +316,20 @@
6             # join_table: name of the m2m link table
7             # source_col_name: the PK colname in join_table for the source object
8             # target_col_name: the PK colname in join_table for the target object
9-            # *objs - objects to add
10+            # *objs - objects to add. Either object instances, or primary keys of object instances.
11             from django.db import connection
12 
13             # If there aren't any objects, there is nothing to do.
14             if objs:
15                 # Check that all the objects are of the right type
16+                new_ids = set()
17                 for obj in objs:
18-                    if not isinstance(obj, self.model):
19-                        raise ValueError, "objects to add() must be %s instances" % self.model._meta.object_name
20+                    if isinstance(obj, self.model):
21+                        new_ids.add(obj._get_pk_val())
22+                    else:
23+                        new_ids.add(obj)
24                 # Add the newly created or already existing objects to the join table.
25                 # First find out which items are already added, to avoid adding them twice
26-                new_ids = set([obj._get_pk_val() for obj in objs])
27                 cursor = connection.cursor()
28                 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
29                     (target_col_name, self.join_table, source_col_name,
30@@ -354,11 +356,13 @@
31             # If there aren't any objects, there is nothing to do.
32             if objs:
33                 # Check that all the objects are of the right type
34+                old_ids = set()
35                 for obj in objs:
36-                    if not isinstance(obj, self.model):
37-                        raise ValueError, "objects to remove() must be %s instances" % self.model._meta.object_name
38+                    if isinstance(obj, self.model):
39+                        old_ids.add(obj._get_pk_val())
40+                    else:
41+                        old_ids.add(obj)
42                 # Remove the specified objects from the join table
43-                old_ids = set([obj._get_pk_val() for obj in objs])
44                 cursor = connection.cursor()
45                 cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
46                     (self.join_table, source_col_name,
47Index: tests/modeltests/many_to_many/models.py
48===================================================================
49--- tests/modeltests/many_to_many/models.py     (revision 4427)
50+++ tests/modeltests/many_to_many/models.py     (working copy)
51@@ -203,7 +203,19 @@
52 >>> p2.article_set.all()
53 [<Article: Oxygen-free diet works wonders>]
54 
55-# Recreate the article and Publication we just deleted.
56+# Relation sets can also be set using primary key values
57+>>> p2.article_set = [a4.id, a5.id]
58+>>> p2.article_set.all()
59+[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>]
60+>>> a4.publications.all()
61+[<Publication: Science News>]
62+>>> a4.publications = [p3.id]
63+>>> p2.article_set.all()
64+[<Article: Oxygen-free diet works wonders>]
65+>>> a4.publications.all()
66+[<Publication: Science Weekly>]
67+
68+# Recreate the article and Publication we have deleted.
69 >>> p1 = Publication(id=None, title='The Python Journal')
70 >>> p1.save()
71 >>> a2 = Article(id=None, headline='NASA uses Python')