Ticket #15184: foreignkey_subclass_patch.diff

File foreignkey_subclass_patch.diff, 4.3 KB (added by furious_luke, 13 years ago)

Patch to correct a bug in subclass ForeignKeyField.

  • django/db/models/fields/subclassing.py

     
    2222    """
    2323    A placeholder class that provides a way to set the attribute on the model.
    2424    """
    25     def __init__(self, field):
     25    def __init__(self, field, old_descr=None):
    2626        self.field = field
     27        self.old_descr = old_descr
    2728
    2829    def __get__(self, obj, type=None):
    2930        if obj is None:
    3031            raise AttributeError('Can only be accessed via an instance.')
    31         return obj.__dict__[self.field.name]
     32        if self.old_descr:
     33            return self.old_descr.__get__(obj, type)
     34        else:
     35            return obj.__dict__[self.field.name]
    3236
    3337    def __set__(self, obj, value):
    34         obj.__dict__[self.field.name] = self.field.to_python(value)
     38        val = self.field.to_python(value)
     39        if self.old_descr:
     40            self.old_descr.__set__(obj, val)
     41        else:
     42            obj.__dict__[self.field.name] = val
    3543
    3644def make_contrib(superclass, func=None):
    3745    """
     
    4755            func(self, cls, name)
    4856        else:
    4957            super(superclass, self).contribute_to_class(cls, name)
    50         setattr(cls, self.name, Creator(self))
     58        # If this value already exists on the class it is likely a descriptor
     59        # for related fields. Keep it around so we can call it from our
     60        # descriptor.
     61        old_descr = cls.__dict__.get(self.name)
     62        setattr(cls, self.name, Creator(self, old_descr))
    5163
    5264    return contribute_to_class
  • tests/modeltests/field_subclassing/tests.py

     
    11from django.core import serializers
    22from django.test import TestCase
     3from django.core.exceptions import ObjectDoesNotExist
    34
    45from fields import Small
    5 from models import DataModel, MyModel, OtherModel
     6from models import DataModel, MyModel, OtherModel, FKModel
    67
    78
    89class CustomField(TestCase):
     
    7980        o = OtherModel.objects.get()
    8081        self.assertEqual(o.data.first, "a")
    8182        self.assertEqual(o.data.second, "b")
     83
     84    def test_foreignkey_subclassing(self):
     85        obj = FKModel()
     86
     87        # We have to do something a bit funky to catch this exception due to
     88        # it originating in a descriptor.
     89        okay = False
     90        try:
     91            # The next line would have raised a KeyError prior to being fixed.
     92            val = obj.data
     93        except ObjectDoesNotExist:
     94            okay = True
     95        self.assertEquals(okay, True)
     96
     97        target = MyModel.objects.create(name="1", data=Small(1, 2))
     98        obj.data = target
     99        obj.save()
     100        self.assertEqual(obj.data, target)
  • tests/modeltests/field_subclassing/models.py

     
    55from django.db import models
    66from django.utils.encoding import force_unicode
    77
    8 from fields import Small, SmallField, SmallerField, JSONField
     8from fields import Small, SmallField, SmallerField, JSONField, FKSubField
    99
    1010
    1111class MyModel(models.Model):
     
    2020
    2121class DataModel(models.Model):
    2222    data = JSONField()
     23
     24
     25class FKModel(models.Model):
     26    data = FKSubField(MyModel)
  • tests/modeltests/field_subclassing/fields.py

     
    7171        if value is None:
    7272            return None
    7373        return json.dumps(value)
     74
     75
     76class FKSubField(models.ForeignKey):
     77    """
     78    Subclass ForeignKey to check descriptor overloading. Confirms ticket
     79    #15184 has been corrected.
     80    """
     81    __metaclass__ = models.SubfieldBase
     82
     83    def __init__(self, cls, *args, **kwargs):
     84        super(FKSubField, self).__init__(cls, *args, **kwargs)
     85
     86    def to_python(self, value):
     87        return value
Back to Top