summaryrefslogtreecommitdiffstats
path: root/webapp/django/db/models/fields/subclassing.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/django/db/models/fields/subclassing.py')
-rw-r--r--webapp/django/db/models/fields/subclassing.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/webapp/django/db/models/fields/subclassing.py b/webapp/django/db/models/fields/subclassing.py
new file mode 100644
index 0000000000..10add10739
--- /dev/null
+++ b/webapp/django/db/models/fields/subclassing.py
@@ -0,0 +1,50 @@
+"""
+Convenience routines for creating non-trivial Field subclasses.
+
+Add SubfieldBase as the __metaclass__ for your Field subclass, implement
+to_python() and the other necessary methods and everything will work seamlessly.
+"""
+
+class SubfieldBase(type):
+ """
+ A metaclass for custom Field subclasses. This ensures the model's attribute
+ has the descriptor protocol attached to it.
+ """
+ def __new__(cls, base, name, attrs):
+ new_class = super(SubfieldBase, cls).__new__(cls, base, name, attrs)
+ new_class.contribute_to_class = make_contrib(
+ attrs.get('contribute_to_class'))
+ return new_class
+
+class Creator(object):
+ """
+ A placeholder class that provides a way to set the attribute on the model.
+ """
+ def __init__(self, field):
+ self.field = field
+
+ def __get__(self, obj, type=None):
+ if obj is None:
+ raise AttributeError('Can only be accessed via an instance.')
+ return obj.__dict__[self.field.name]
+
+ def __set__(self, obj, value):
+ obj.__dict__[self.field.name] = self.field.to_python(value)
+
+def make_contrib(func=None):
+ """
+ Returns a suitable contribute_to_class() method for the Field subclass.
+
+ If 'func' is passed in, it is the existing contribute_to_class() method on
+ the subclass and it is called before anything else. It is assumed in this
+ case that the existing contribute_to_class() calls all the necessary
+ superclass methods.
+ """
+ def contribute_to_class(self, cls, name):
+ if func:
+ func(self, cls, name)
+ else:
+ super(self.__class__, self).contribute_to_class(cls, name)
+ setattr(cls, self.name, Creator(self))
+
+ return contribute_to_class