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 | """} |