mise-en-production
[auf_framonde.git] / project / cmsplugin_contact_plus / jsonfield / subclassing.py
1 ## This file was copied from django.db.models.fields.subclassing so that we could
2 ## change the Creator.__set__ behavior. Read the comment below for full details.
3
4 """
5 Convenience routines for creating non-trivial Field subclasses, as well as
6 backwards compatibility utilities.
7
8 Add SubfieldBase as the __metaclass__ for your Field subclass, implement
9 to_python() and the other necessary methods and everything will work seamlessly.
10 """
11
12 class SubfieldBase(type):
13 """
14 A metaclass for custom Field subclasses. This ensures the model's attribute
15 has the descriptor protocol attached to it.
16 """
17 def __new__(cls, name, bases, attrs):
18 new_class = super(SubfieldBase, cls).__new__(cls, name, bases, attrs)
19 new_class.contribute_to_class = make_contrib(
20 new_class, attrs.get('contribute_to_class')
21 )
22 return new_class
23
24 class Creator(object):
25 """
26 A placeholder class that provides a way to set the attribute on the model.
27 """
28 def __init__(self, field):
29 self.field = field
30
31 def __get__(self, obj, type=None):
32 if obj is None:
33 raise AttributeError('Can only be accessed via an instance.')
34 return obj.__dict__[self.field.name]
35
36 def __set__(self, obj, value):
37 # Usually this would call to_python, but we've changed it to pre_init
38 # so that we can tell which state we're in. By passing an obj,
39 # we can definitively tell if a value has already been deserialized
40 # More: https://github.com/bradjasper/django-jsonfield/issues/33
41 obj.__dict__[self.field.name] = self.field.pre_init(value, obj)
42
43
44 def make_contrib(superclass, func=None):
45 """
46 Returns a suitable contribute_to_class() method for the Field subclass.
47
48 If 'func' is passed in, it is the existing contribute_to_class() method on
49 the subclass and it is called before anything else. It is assumed in this
50 case that the existing contribute_to_class() calls all the necessary
51 superclass methods.
52 """
53 def contribute_to_class(self, cls, name):
54 if func:
55 func(self, cls, name)
56 else:
57 super(superclass, self).contribute_to_class(cls, name)
58 setattr(cls, self.name, Creator(self))
59
60 return contribute_to_class