14 |
14 |
# You should have received a copy of the GNU Affero General Public License
|
15 |
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16 |
16 |
|
17 |
|
import inspect
|
18 |
|
|
19 |
17 |
import django
|
20 |
18 |
from django.db import connection
|
21 |
19 |
from django.db.utils import OperationalError
|
... | ... | |
33 |
31 |
except (ImproperlyConfigured, OperationalError):
|
34 |
32 |
# database is not initialized, be conservative
|
35 |
33 |
return False
|
36 |
|
|
37 |
|
|
38 |
|
def use_django_native_field():
|
39 |
|
return has_postgresql_support() and django.VERSION >= (1, 11)
|
40 |
|
|
41 |
|
|
42 |
|
class JSONField(object):
|
43 |
|
__dj11_field = None
|
44 |
|
__jsonfield_field = None
|
45 |
|
__name = None
|
46 |
|
|
47 |
|
def __init__(self, *args, **kwargs):
|
48 |
|
self.__args = args
|
49 |
|
self.__kwargs = kwargs
|
50 |
|
if django.VERSION >= (1, 11):
|
51 |
|
try:
|
52 |
|
from django.contrib.postgres.fields import JSONField
|
53 |
|
self.__dj11_field = JSONField(*args, **kwargs)
|
54 |
|
except ImportError:
|
55 |
|
pass
|
56 |
|
try:
|
57 |
|
from jsonfield.fields import JSONField
|
58 |
|
self.__jsonfield_field = JSONField(*args, **kwargs)
|
59 |
|
except ImportError:
|
60 |
|
pass
|
61 |
|
|
62 |
|
def __real_field__(self):
|
63 |
|
if use_django_native_field():
|
64 |
|
assert self.__dj11_field
|
65 |
|
return self.__dj11_field
|
66 |
|
assert self.__jsonfield_field
|
67 |
|
return self.__jsonfield_field
|
68 |
|
|
69 |
|
def __getattr__(self, key):
|
70 |
|
return getattr(self.__real_field__(), key)
|
71 |
|
|
72 |
|
def __setattr__(self, key, value):
|
73 |
|
if key.startswith('_JSONField__'):
|
74 |
|
super(JSONField, self).__setattr__(key, value)
|
75 |
|
else:
|
76 |
|
setattr(self.__real__field(), key, value)
|
77 |
|
|
78 |
|
# we need to implement contribute_to_class so that the direct
|
79 |
|
# implementation from the two sub-fields is not used directly
|
80 |
|
def contribute_to_class(self, cls, name, private_only=False, virtual_only=False, **kwargs):
|
81 |
|
assert not virtual_only and not private_only, 'virtual_only / private_only are not supported'
|
82 |
|
assert not kwargs, 'new arguments to contribute_to_class not supported'
|
83 |
|
self.__name = name
|
84 |
|
if self.__dj11_field:
|
85 |
|
self.__dj11_field.set_attributes_from_name(name)
|
86 |
|
self.__dj11_field.model = cls
|
87 |
|
if self.__jsonfield_field:
|
88 |
|
self.__jsonfield_field.set_attributes_from_name(name)
|
89 |
|
self.__jsonfield_field.model = cls
|
90 |
|
cls._meta.add_field(self)
|
91 |
|
|
92 |
|
# the next two methods are useful for compatibilit with the migration engine
|
93 |
|
# inspect is used because migration autodetector cannot recognize this class
|
94 |
|
# as a subclass of models.Field.
|
95 |
|
def deconstruct(self):
|
96 |
|
d = (self.__name, 'authentic2.compat.JSONField', self.__args, self.__kwargs)
|
97 |
|
previous_frame = inspect.currentframe().f_back
|
98 |
|
if inspect.getframeinfo(previous_frame)[2] in ('serialize', 'deep_deconstruct'):
|
99 |
|
d = d[1:]
|
100 |
|
return d
|
101 |
|
|
102 |
|
def clone(self):
|
103 |
|
from copy import copy
|
104 |
|
new = copy(self)
|
105 |
|
if self.__dj11_field:
|
106 |
|
new.__dj11_field = new.__dj11_field.clone()
|
107 |
|
if self.__jsonfield_field:
|
108 |
|
new.__jsonfield_field = new.__jsonfield_field.clone()
|
109 |
|
return new
|
110 |
|
|
111 |
|
|
112 |
|
try:
|
113 |
|
import jsonfield.fields
|
114 |
|
except ImportError:
|
115 |
|
pass
|
116 |
|
else:
|
117 |
|
# prevent django-jsonfield from modifying postgresql connection when we are
|
118 |
|
# not using it
|
119 |
|
if hasattr(jsonfield.fields, 'connection_created'):
|
120 |
|
def configure_database_connection(connection, **kwargs):
|
121 |
|
if django.VERSION < (1, 11):
|
122 |
|
jsonfield.fields.configure_database_connection(connection, **kwargs)
|
123 |
|
jsonfield.fields.connection_created.disconnect(jsonfield.fields.configure_database_connection)
|
124 |
|
jsonfield.fields.connection_created.connect(configure_database_connection)
|