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