From b93e44c8b0c875c4407a00a9b02c92540e25e094 Mon Sep 17 00:00:00 2001
From: Gabriel <g2p.code@gmail.com>
Date: Sat, 4 Apr 2009 02:22:01 +0200
Subject: [PATCH] Allow subclassing field types that use the SubfieldBase metaclass.
Includes a test that used to fail but now doesn't.
---
django/db/models/fields/subclassing.py | 6 ++--
tests/modeltests/field_subclassing/models.py | 30 ++++++++++++++++++++++++++
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/django/db/models/fields/subclassing.py b/django/db/models/fields/subclassing.py
index bd11675..ea100fd 100644
a
|
b
|
class SubfieldBase(LegacyConnection):
|
79 | 79 | def __new__(cls, base, name, attrs): |
80 | 80 | new_class = super(SubfieldBase, cls).__new__(cls, base, name, attrs) |
81 | 81 | new_class.contribute_to_class = make_contrib( |
82 | | attrs.get('contribute_to_class')) |
| 82 | attrs.get('contribute_to_class'), new_class) |
83 | 83 | return new_class |
84 | 84 | |
85 | 85 | class Creator(object): |
… |
… |
class Creator(object):
|
97 | 97 | def __set__(self, obj, value): |
98 | 98 | obj.__dict__[self.field.name] = self.field.to_python(value) |
99 | 99 | |
100 | | def make_contrib(func=None): |
| 100 | def make_contrib(func, field_class): |
101 | 101 | """ |
102 | 102 | Returns a suitable contribute_to_class() method for the Field subclass. |
103 | 103 | |
… |
… |
def make_contrib(func=None):
|
110 | 110 | if func: |
111 | 111 | func(self, cls, name) |
112 | 112 | else: |
113 | | super(self.__class__, self).contribute_to_class(cls, name) |
| 113 | super(field_class, self).contribute_to_class(cls, name) |
114 | 114 | setattr(cls, self.name, Creator(self)) |
115 | 115 | |
116 | 116 | return contribute_to_class |
diff --git a/tests/modeltests/field_subclassing/models.py b/tests/modeltests/field_subclassing/models.py
index c776146..09faf1c 100644
a
|
b
|
class SmallField(models.Field):
|
53 | 53 | return [] |
54 | 54 | raise FieldError('Invalid lookup type: %r' % lookup_type) |
55 | 55 | |
| 56 | class OtherField(SmallField): |
| 57 | """ |
| 58 | Check the SubfieldBase metaclass works with inheritance. |
| 59 | """ |
| 60 | |
| 61 | pass |
| 62 | |
| 63 | def make_othermodel(): |
| 64 | """ |
| 65 | Isolate OtherModel class definition. |
| 66 | |
| 67 | When the test fails, it fails at class definition with a long |
| 68 | stack trace. This confuses test discovery, so wrap it in a function. |
| 69 | """ |
| 70 | |
| 71 | try: |
| 72 | class OtherModel(models.Model): |
| 73 | other_data = OtherField(default='example') |
| 74 | except RuntimeError: # Maximum recursion depth |
| 75 | raise RuntimeError("Couldn't subclass field") |
| 76 | else: |
| 77 | return OtherModel |
| 78 | |
56 | 79 | class MyModel(models.Model): |
57 | 80 | name = models.CharField(max_length=10) |
58 | 81 | data = SmallField('small field') |
… |
… |
FieldError: Invalid lookup type: 'lt'
|
102 | 125 | >>> obj.object == m |
103 | 126 | True |
104 | 127 | |
| 128 | # Test custom field subclassing. |
| 129 | >>> OtherModel = make_othermodel() |
| 130 | >>> om = OtherModel() |
| 131 | >>> om.other_data = 'plop' |
| 132 | >>> str(om.other_data) |
| 133 | "pl" |
| 134 | |
105 | 135 | # Test retrieving custom field data |
106 | 136 | >>> m.delete() |
107 | 137 | >>> m1 = MyModel(name="1", data=Small(1, 2)) |