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