Ticket #10728: SubfieldBase-#10728-r12890.patch
File SubfieldBase-#10728-r12890.patch, 4.1 KB (added by , 15 years ago) |
---|
-
django/db/models/fields/subclassing.py
76 76 A metaclass for custom Field subclasses. This ensures the model's attribute 77 77 has the descriptor protocol attached to it. 78 78 """ 79 def __new__(cls, base, name, attrs): 80 new_class = super(SubfieldBase, cls).__new__(cls, base, name, attrs) 81 new_class.contribute_to_class = make_contrib( 82 attrs.get('contribute_to_class')) 83 return new_class 79 def __init__(cls, name, base, attrs): 80 def contribute_to_class(self, model_cls, name): 81 assert isinstance(self, cls) 82 super(cls, self).contribute_to_class(model_cls, name) 83 setattr(model_cls, name, Creator(self)) 84 cls.contribute_to_class = contribute_to_class 84 85 85 86 class Creator(object): 86 87 """ … … 96 97 97 98 def __set__(self, obj, value): 98 99 obj.__dict__[self.field.name] = self.field.to_python(value) 99 100 def make_contrib(func=None):101 """102 Returns a suitable contribute_to_class() method for the Field subclass.103 104 If 'func' is passed in, it is the existing contribute_to_class() method on105 the subclass and it is called before anything else. It is assumed in this106 case that the existing contribute_to_class() calls all the necessary107 superclass methods.108 """109 def contribute_to_class(self, cls, name):110 if func:111 func(self, cls, name)112 else:113 super(self.__class__, self).contribute_to_class(cls, name)114 setattr(cls, self.name, Creator(self))115 116 return contribute_to_class -
tests/modeltests/field_subclassing/models.py
6 6 from django.db import models 7 7 from django.utils.encoding import force_unicode 8 8 9 from fields import Small, SmallField, JSONField9 from fields import Small, SmallField, SmallerField, JSONField 10 10 11 11 12 12 class MyModel(models.Model): … … 19 19 class DataModel(models.Model): 20 20 data = JSONField() 21 21 22 def make_smallermodel(): 23 """ 24 Isolate SmallerModel class definition. 25 26 When the test fails, it fails at class definition with a long 27 stack trace. This confuses test discovery, so wrap it in a function. 28 """ 29 try: 30 class SmallerModel(models.Model): 31 other_data = SmallerField(default='example') 32 except RuntimeError: # Maximum recursion depth 33 raise RuntimeError("Couldn't subclass field") 34 else: 35 return SmallerModel 36 22 37 __test__ = {'API_TESTS': ur""" 23 38 # Creating a model with custom fields is done as per normal. 24 39 >>> s = Small(1, 2) … … 61 76 >>> obj.object == m 62 77 True 63 78 79 # Test custom field subclassing. 80 >>> SmallerModel = make_smallermodel() 81 >>> sm = SmallerModel() 82 >>> sm.other_data = 'plop' 83 >>> str(sm.other_data) 84 "pl" 85 64 86 # Test retrieving custom field data 65 87 >>> m.delete() 66 88 >>> m1 = MyModel(name="1", data=Small(1, 2)) -
tests/modeltests/field_subclassing/fields.py
51 51 raise TypeError('Invalid lookup type: %r' % lookup_type) 52 52 53 53 54 class SmallerField(SmallField): 55 """ 56 Checks that the SubfieldBase metaclass works with inheritance. 57 """ 58 54 59 class JSONField(models.TextField): 55 60 __metaclass__ = models.SubfieldBase 56 61 57 62 description = ("JSONField automatically serializes and desializes values to " 58 63 "and from JSON.") 59 64 60 65 def to_python(self, value): 61 66 if not value: 62 67 return None 63 64 68 if isinstance(value, basestring): 65 69 value = json.loads(value) 66 70 return value 67 71 68 72 def get_db_prep_save(self, value): 69 73 if value is None: 70 74 return None