authentic/src/authentic2/compat.py

120 lines
4.1 KiB
Python

from datetime import datetime
import inspect
import django
from django.conf import settings
from django.db import connection
from django.contrib.auth.tokens import PasswordResetTokenGenerator
try:
from django.contrib.auth import get_user_model
except ImportError:
from django.contrib.auth.models import User
get_user_model = lambda: User
try:
from django.db.transaction import atomic
commit_on_success = atomic
except ImportError:
from django.db.transaction import commit_on_success
user_model_label = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
default_token_generator = PasswordResetTokenGenerator()
def has_postgresql_support():
if not settings.DATABASES['default'].get('NAME'):
return False
return connection.vendor == 'postgresql' and connection.pg_version > 90400
def use_django_native_field():
return has_postgresql_support() and django.VERSION >= (1, 11)
class JSONField(object):
__dj11_field = None
__jsonfield_field = None
__name = None
def __init__(self, *args, **kwargs):
self.__args = args
self.__kwargs = kwargs
if django.VERSION >= (1, 11):
try:
from django.contrib.postgres.fields import JSONField
self.__dj11_field = JSONField(*args, **kwargs)
except ImportError:
pass
try:
from jsonfield.fields import JSONField
self.__jsonfield_field = JSONField(*args, **kwargs)
except ImportError:
pass
def __real_field__(self):
if use_django_native_field():
assert self.__dj11_field
return self.__dj11_field
assert self.__jsonfield_field
return self.__jsonfield_field
def __getattr__(self, key):
return getattr(self.__real_field__(), key)
def __setattr__(self, key, value):
if key.startswith('_JSONField__'):
super(JSONField, self).__setattr__(key, value)
else:
setattr(self.__real__field(), key, value)
# we need to implement contribute_to_class so that the direct
# implementation from the two sub-fields is not used directly
def contribute_to_class(self, cls, name, private_only=False, virtual_only=False, **kwargs):
assert not virtual_only and not private_only, 'virtual_only / private_only are not supported'
assert not kwargs, 'new arguments to contribute_to_class not supported'
self.__name = name
if self.__dj11_field:
self.__dj11_field.set_attributes_from_name(name)
self.__dj11_field.model = cls
if self.__jsonfield_field:
self.__jsonfield_field.set_attributes_from_name(name)
self.__jsonfield_field.model = cls
cls._meta.add_field(self)
# the next two methods are useful for compatibilit with the migration engine
# inspect is used because migration autodetector cannot recognize this class
# as a subclass of models.Field.
def deconstruct(self):
d = (self.__name, 'authentic2.compat.JSONField', self.__args, self.__kwargs)
previous_frame = inspect.currentframe().f_back
if inspect.getframeinfo(previous_frame)[2] in ('serialize', 'deep_deconstruct'):
d = d[1:]
return d
def clone(self):
from copy import copy
new = copy(self)
if self.__dj11_field:
new.__dj11_field = new.__dj11_field.clone()
if self.__jsonfield_field:
new.__jsonfield_field = new.__jsonfield_field.clone()
return new
try:
import jsonfield.fields
except ImportError:
pass
else:
# prevent django-jsonfield from modifying postgresql connection when we are
# not using it
if hasattr(jsonfield.fields, 'connection_created'):
def configure_database_connection(connection, **kwargs):
if django.VERSION < (1, 11):
jsonfield.fields.configure_database_connection(connection, **kwargs)
jsonfield.fields.connection_created.disconnect(jsonfield.fields.configure_database_connection)
jsonfield.fields.connection_created.connect(configure_database_connection)