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)) |