Code

Ticket #14615: 14615.diff

File 14615.diff, 4.8 KB (added by lukeplant, 3 years ago)

patch - throw exception rather than do a query for unsaved instances

Line 
1diff -r 24c30016c52f django/db/models/base.py
2--- a/django/db/models/base.py  Tue Dec 14 00:37:42 2010 +0000
3+++ b/django/db/models/base.py  Thu Dec 16 14:33:17 2010 +0000
4@@ -585,7 +585,7 @@
5         return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True)
6 
7     def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
8-        if not self.pk:
9+        if self._state.adding:
10             raise ValueError("get_next/get_previous cannot be used on unsaved objects.")
11         op = is_next and 'gt' or 'lt'
12         order = not is_next and '-' or ''
13diff -r 24c30016c52f django/db/models/fields/related.py
14--- a/django/db/models/fields/related.py        Tue Dec 14 00:37:42 2010 +0000
15+++ b/django/db/models/fields/related.py        Thu Dec 16 14:33:17 2010 +0000
16@@ -223,6 +223,9 @@
17         try:
18             return getattr(instance, self.cache_name)
19         except AttributeError:
20+            if instance._state.adding:
21+                raise ValueError("Cannot retrieve related objects until the instance has been saved")
22+
23             params = {'%s__pk' % self.related.field.name: instance._get_pk_val()}
24             db = router.db_for_read(self.related.model, instance=instance)
25             rel_obj = self.related.model._base_manager.using(db).get(**params)
26@@ -454,6 +457,9 @@
27 
28         manager = RelatedManager()
29         attname = rel_field.rel.get_related_field().name
30+
31+        if instance._state.adding:
32+            raise ValueError("Cannot retrieve related objects until the instance has been saved")
33         manager.core_filters = {'%s__%s' % (rel_field.name, attname):
34                 getattr(instance, attname)}
35         manager.model = self.related.model
36@@ -478,8 +484,8 @@
37             self.through = through
38             self._pk_val = self.instance.pk
39             self.reverse = reverse
40-            if self._pk_val is None:
41-                raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)
42+            if self.instance._state.adding:
43+                raise ValueError("%r instance needs to be saved before a many-to-many relationship can be used." % instance.__class__.__name__)
44 
45         def get_query_set(self):
46             db = self._db or router.db_for_read(self.instance.__class__, instance=self.instance)
47diff -r 24c30016c52f tests/modeltests/lookup/tests.py
48--- a/tests/modeltests/lookup/tests.py  Tue Dec 14 00:37:42 2010 +0000
49+++ b/tests/modeltests/lookup/tests.py  Thu Dec 16 14:33:17 2010 +0000
50@@ -350,6 +350,7 @@
51                          '<Article: Article 2>')
52         self.assertEqual(repr(self.a2.get_previous_by_pub_date()),
53                          '<Article: Article 1>')
54+        self.assertRaises(ValueError, lambda: Article().get_previous_by_pub_date())
55 
56     def test_escaping(self):
57         # Underscores, percent signs and backslashes have special meaning in the
58diff -r 24c30016c52f tests/modeltests/many_to_one/tests.py
59--- a/tests/modeltests/many_to_one/tests.py     Tue Dec 14 00:37:42 2010 +0000
60+++ b/tests/modeltests/many_to_one/tests.py     Thu Dec 16 14:33:17 2010 +0000
61@@ -370,3 +370,8 @@
62         self.r.cached_query = Article.objects.filter(reporter=self.r)
63         from copy import deepcopy
64         self.assertEqual(repr(deepcopy(self.r)), "<Reporter: John Smith>")
65+
66+    def test_related_before_save(self):
67+        # You cannot get the related objects before the main object is saved.
68+        # See ticket #14615
69+        self.assertRaises(ValueError, getattr, Reporter(), 'article_set')
70diff -r 24c30016c52f tests/modeltests/one_to_one/tests.py
71--- a/tests/modeltests/one_to_one/tests.py      Tue Dec 14 00:37:42 2010 +0000
72+++ b/tests/modeltests/one_to_one/tests.py      Thu Dec 16 14:33:17 2010 +0000
73@@ -117,3 +117,8 @@
74         mm = MultiModel(link1=self.p2, link2=o1, name="x1")
75         self.assertRaises(IntegrityError, mm.save)
76         transaction.savepoint_rollback(sid)
77+
78+    def test_related_before_save(self):
79+        # You cannot get the related objects before the main object is saved.
80+        # See ticket #14615
81+        self.assertRaises(ValueError, getattr, Place(), 'restaurant')
82diff -r 24c30016c52f tests/regressiontests/null_queries/tests.py
83--- a/tests/regressiontests/null_queries/tests.py       Tue Dec 14 00:37:42 2010 +0000
84+++ b/tests/regressiontests/null_queries/tests.py       Thu Dec 16 14:33:17 2010 +0000
85@@ -42,10 +42,6 @@
86         # Can't use None on anything other than __exact
87         self.assertRaises(ValueError, Choice.objects.filter, foo__gt=None)
88 
89-        # Related managers use __exact=None implicitly if the object hasn't been saved.
90-        p2 = Poll(question="How?")
91-        self.assertEquals(repr(p2.choice_set.all()), '[]')
92-
93     def test_reverse_relations(self):
94         """
95         Querying across reverse relations and then another relation should