diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index e3677c2..e6f651d 100644
a
|
b
|
class ReverseSingleRelatedObjectDescriptor(object):
|
225 | 225 | def __set__(self, instance, value): |
226 | 226 | if instance is None: |
227 | 227 | raise AttributeError, "%s must be accessed via instance" % self._field.name |
| 228 | |
| 229 | # If null=True, we can assign null here, but otherwise the value needs |
| 230 | # to be an instance of the related class. |
| 231 | if value is None and self.field.null == False: |
| 232 | raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' % |
| 233 | (instance._meta.object_name, self.field.name)) |
| 234 | elif value is not None and not isinstance(value, self.field.rel.to): |
| 235 | raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' % |
| 236 | (value, instance._meta.object_name, |
| 237 | self.field.name, self.field.rel.to._meta.object_name)) |
| 238 | |
228 | 239 | # Set the value of the related field |
229 | 240 | try: |
230 | 241 | val = getattr(value, self.field.rel.get_related_field().attname) |
… |
… |
class ReverseSingleRelatedObjectDescriptor(object):
|
232 | 243 | val = None |
233 | 244 | setattr(instance, self.field.attname, val) |
234 | 245 | |
235 | | # Clear the cache, if it exists |
236 | | try: |
237 | | delattr(instance, self.field.get_cache_name()) |
238 | | except AttributeError: |
239 | | pass |
| 246 | # Since we already know what the related object is, seed the related |
| 247 | # object cache now, too. This avoids another db hit if you get the |
| 248 | # object you just set. |
| 249 | setattr(instance, self.field.get_cache_name(), value) |
240 | 250 | |
241 | 251 | class ForeignRelatedObjectsDescriptor(object): |
242 | 252 | # This class provides the functionality that makes the related-object |
diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py
index 57bbcd8..012ccbe 100644
a
|
b
|
class Child(models.Model):
|
25 | 25 | |
26 | 26 | |
27 | 27 | __test__ = {'API_TESTS':""" |
28 | | >>> Third.AddManipulator().save(dict(id='3', name='An example', another=None)) |
| 28 | >>> Third.objects.create(id='3', name='An example') |
29 | 29 | <Third: Third object> |
30 | 30 | >>> parent = Parent(name = 'fred') |
31 | 31 | >>> parent.save() |
32 | | >>> Child.AddManipulator().save(dict(name='bam-bam', parent=parent.id)) |
| 32 | >>> Child.objects.create(name='bam-bam', parent=parent) |
33 | 33 | <Child: Child object> |
| 34 | |
| 35 | # |
| 36 | # Tests of ForeignKey assignment and the related-object cache (see #6886) |
| 37 | # |
| 38 | >>> p = Parent.objects.create(name="Parent") |
| 39 | >>> c = Child.objects.create(name="Child", parent=p) |
| 40 | |
| 41 | # Look up the object again so that we get a "fresh" object |
| 42 | >>> c = Child.objects.get(name="Child") |
| 43 | >>> p = c.parent |
| 44 | |
| 45 | # Accessing the related object again returns the exactly same object |
| 46 | >>> c.parent is p |
| 47 | True |
| 48 | |
| 49 | # But if we kill the cache, we get a new object |
| 50 | >>> del c._parent_cache |
| 51 | >>> c.parent is p |
| 52 | False |
| 53 | |
| 54 | # Here's where the changes discussed in #6886 (and committed in [XXXX]) start: |
| 55 | |
| 56 | # Assigning a new object results in that object getting cached immediately |
| 57 | >>> p2 = Parent.objects.create(name="Parent 2") |
| 58 | >>> c.parent = p2 |
| 59 | >>> c.parent is p2 |
| 60 | True |
| 61 | |
| 62 | # Assigning None fails: Child.parent is null=False |
| 63 | >>> c.parent = None |
| 64 | Traceback (most recent call last): |
| 65 | ... |
| 66 | ValueError: Cannot assign None: "Child.parent" does not allow null values. |
| 67 | |
| 68 | # You also can't assign an object of the wrong type here |
| 69 | >>> c.parent = First(id=1, second=1) |
| 70 | Traceback (most recent call last): |
| 71 | ... |
| 72 | ValueError: Cannot assign "<First: First object>": "Child.parent" must be a "Parent" instance. |
| 73 | |
34 | 74 | """} |