2016-11-24 3 views
0

とallauthシリアル化エラーカスタムUserモデルマイカスタムUserモデルはTimeZoneFieldを持っている:DjangoはTimeZoneField

from timezone_field import TimeZoneField 


class User(AbstractBaseUser, PermissionsMixin): 

    class Meta: 
     verbose_name = _('user') 
     verbose_name_plural = _('users') 

    email = models.EmailField(_('email address'), unique=True, blank=False, null=False) 
    username = models.CharField(_('user name'), max_length=128, unique=True, blank=False, null=False) 

    is_staff = models.BooleanField(
     _('staff status'), 
     default=False, 
     help_text=_('Designates whether the user can log into this admin site.')) 
    is_active = models.BooleanField(
     _('active'), 
     default=True, 
     help_text=_(
      'Designates whether this user should be treated as active. ' 
      'Unselect this instead of deleting accounts.')) 
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now) 

    language = models.CharField(_('Language'), choices=settings.LANGUAGES, default=settings.ENGLISH, max_length=2) 
    timezone = TimeZoneField(verbose_name=_('Timezone'), default='Europe/London') 

    objects = UserManager() 

    USERNAME_FIELD = 'username' 
    REQUIRED_FIELDS = ['email'] 

私は、Googleアカウントで登録のためのジャンゴ - allauthを使用しています。既存のユーザー(前にGoogleの電子メールによって登録、いないGoogleアカウント)私たちがエラーを持っているGoogleアカウントでログインをしようとすると:

<DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD> is not JSON serializable 


Traceback: 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response 
    149.      response = self.process_exception_by_middleware(e, request) 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response 
    147.      response = wrapped_callback(request, *callback_args, **callback_kwargs) 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/allauth/socialaccount/providers/oauth2/views.py" in view 
    55.    return self.dispatch(request, *args, **kwargs) 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/allauth/socialaccount/providers/oauth2/views.py" in dispatch 
    125.    return complete_social_login(request, login) 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/allauth/socialaccount/helpers.py" in complete_social_login 
    142.   return _complete_social_login(request, sociallogin) 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/allauth/socialaccount/helpers.py" in _complete_social_login 
    158.   ret = _process_signup(request, sociallogin) 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/allauth/socialaccount/helpers.py" in _process_signup 
    25.   request.session['socialaccount_sociallogin'] = sociallogin.serialize() 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/allauth/socialaccount/models.py" in serialize 
    189.     user=serialize_instance(self.user), 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/allauth/utils.py" in serialize_instance 
    194.  return json.loads(json.dumps(data, cls=DjangoJSONEncoder)) 

File "/usr/lib/python3.4/json/__init__.py" in dumps 
    237.   **kw).encode(obj) 

File "/usr/lib/python3.4/json/encoder.py" in encode 
    192.   chunks = self.iterencode(o, _one_shot=True) 

File "/usr/lib/python3.4/json/encoder.py" in iterencode 
    250.   return _iterencode(o, 0) 

File "/webapps/myproject/tmp/venv/lib/python3.4/site-packages/django/core/serializers/json.py" in default 
    115.    return super(DjangoJSONEncoder, self).default(o) 

File "/usr/lib/python3.4/json/encoder.py" in default 
    173.   raise TypeError(repr(o) + " is not JSON serializable") 

Exception Type: TypeError at /accounts/google/login/callback/ 
Exception Value: <DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD> is not JSON serializable 

allauthにカスタムフィールドをシリアル化するためにいくつかの方法が何ですか?

答えて

0

私の解決策は、TimeZoneFieldをシリアル化するためにdefaultSocialAccountAdapterとextension serialize_instance(allauth.utilsから)を置き換えます。カスタムプロジェクト設定でadapret設定を忘れないでください:

SOCIALACCOUNT_ADAPTER = 'myapp.adapter.MySocialAccountAdapter' 

はまた、私は社会が(電子メールによる登録)Direct口座(彼の例をありがとうelssarhttps://stackoverflow.com/a/19443127/4012716)でアカウントの関連付けのためpre_social_loginを置き換え

myapp.adapter.py:

import json 
import base64 
import logging 


from django.db.models import FieldDoesNotExist, FileField 
from django.db.models.fields import (BinaryField) 
from django.utils import six 
from django.core.serializers.json import DjangoJSONEncoder 
from django.shortcuts import HttpResponse 

try: 
    from django.utils.encoding import force_text 
except ImportError: 
    from django.utils.encoding import force_unicode as force_text 

from allauth.socialaccount.adapter import DefaultSocialAccountAdapter 
from allauth.account.adapter import DefaultAccountAdapter 
from allauth.utils import SERIALIZED_DB_FIELD_PREFIX 
from allauth.exceptions import ImmediateHttpResponse 
from timezone_field import TimeZoneField 

from accounts.models import User 


logger = logging.getLogger("django") 


def my_serialize_instance(instance): 
    """Instance serializer supported of serialization of TimeZoneField. 
    :param instance: 
    :return: 
    """ 
    data = {} 
    for k, v in instance.__dict__.items(): 
     if k.startswith('_') or callable(v): 
      continue 
     try: 
      field = instance._meta.get_field(k) 
      if isinstance(field, BinaryField): 
       v = force_text(base64.b64encode(v)) 
      elif isinstance(field, FileField): 
       if not isinstance(v, six.string_types): 
        v = v.name 
      elif isinstance(field, TimeZoneField): 
       v = six.text_type(v.zone) 
      # Check if the field is serializable. If not, we'll fall back 
      # to serializing the DB values which should cover most use cases. 
      try: 
       json.dumps(v, cls=DjangoJSONEncoder) 
      except TypeError: 
       v = field.get_prep_value(v) 
       k = SERIALIZED_DB_FIELD_PREFIX + k 
     except FieldDoesNotExist: 
      pass 
     data[k] = v 
    return json.loads(json.dumps(data, cls=DjangoJSONEncoder)) 


class MySocialAccountAdapter(DefaultSocialAccountAdapter): 
    """Custom SocialAccountAdapter for django-allauth. 
    Replaced standard behavior for serialization of TimeZoneField. 

    Need set it in project settings: 
    SOCIALACCOUNT_ADAPTER = 'myapp.adapter.MySocialAccountAdapter' 
    """ 

    def __init__(self, request=None): 
     super(MySocialAccountAdapter, self).__init__(request=request) 

    def pre_social_login(self, request, sociallogin): 
     # This isn't tested, but should work 
     try: 
      emails = [email.email for email in sociallogin.email_addresses] 
      user = User.objects.get(email__in=emails) 
      sociallogin.connect(request, user) 
      raise ImmediateHttpResponse(response=HttpResponse()) 
     except User.DoesNotExist: 
      pass 
     except Exception as ex: 
      logger.error(ex) 

    def serialize_instance(self, instance): 
     return my_serialize_instance(instance)