web/lib/django/db/models/fields/subclassing.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 """
       
     2 Convenience routines for creating non-trivial Field subclasses.
       
     3 
       
     4 Add SubfieldBase as the __metaclass__ for your Field subclass, implement
       
     5 to_python() and the other necessary methods and everything will work seamlessly.
       
     6 """
       
     7 
       
     8 class SubfieldBase(type):
       
     9     """
       
    10     A metaclass for custom Field subclasses. This ensures the model's attribute
       
    11     has the descriptor protocol attached to it.
       
    12     """
       
    13     def __new__(cls, base, name, attrs):
       
    14         new_class = super(SubfieldBase, cls).__new__(cls, base, name, attrs)
       
    15         new_class.contribute_to_class = make_contrib(
       
    16                 attrs.get('contribute_to_class'))
       
    17         return new_class
       
    18 
       
    19 class Creator(object):
       
    20     """
       
    21     A placeholder class that provides a way to set the attribute on the model.
       
    22     """
       
    23     def __init__(self, field):
       
    24         self.field = field
       
    25 
       
    26     def __get__(self, obj, type=None):
       
    27         if obj is None:
       
    28             raise AttributeError('Can only be accessed via an instance.')
       
    29         return obj.__dict__[self.field.name]        
       
    30 
       
    31     def __set__(self, obj, value):
       
    32         obj.__dict__[self.field.name] = self.field.to_python(value)
       
    33 
       
    34 def make_contrib(func=None):
       
    35     """
       
    36     Returns a suitable contribute_to_class() method for the Field subclass.
       
    37 
       
    38     If 'func' is passed in, it is the existing contribute_to_class() method on
       
    39     the subclass and it is called before anything else. It is assumed in this
       
    40     case that the existing contribute_to_class() calls all the necessary
       
    41     superclass methods.
       
    42     """
       
    43     def contribute_to_class(self, cls, name):
       
    44         if func:
       
    45             func(self, cls, name)
       
    46         else:
       
    47             super(self.__class__, self).contribute_to_class(cls, name)
       
    48         setattr(cls, self.name, Creator(self))
       
    49 
       
    50     return contribute_to_class