django-rest-auth自定义注册无法保存额外的字段

时间:2016-06-15 17:05:49

标签: django django-rest-framework django-rest-auth

我正在使用DRF并登录/注册我正在使用Django-rest-auth。

  1. 我已定制用户模型以获得额外字段
  2. 我有自定义注册序列化程序,用于在注册新用户时存储额外字段以及用户名,密码。
  3. 注册成功但是,额外的字段不会与username,first_name,last_name和password一起保存。

    我的模特:

    Traceback (most recent call last):
      File "ShearMoment.py", line 63, in <module>
        h[i] = sp.bisect(BeamHeight, hb, 5,xtol = 0.001)
      File "/usr/lib/python2.7/dist-packages/scipy/optimize/zeros.py", line 248, in bisect
        r = _zeros._bisect(f,a,b,xtol,rtol,maxiter,args,full_output,disp)
      File "ShearMoment.py", line 58, in BeamHeight
        x = 1000e3*M[i]*h/(fw*h^3-(fw-wt)(h-2*ft)^3) - Max_stress_steel
    TypeError: 'float' object is not callable
    

    My Serializer:

    class UserManager(BaseUserManager):
    
      def _create_user(self, username, email, password, is_staff, is_superuser, address, **extra_fields):
        now = timezone.now()
        if not username:
          raise ValueError(_('The given username must be set'))
        email = self.normalize_email(email)
        user = self.model(username=username, email=email,
                 is_staff=is_staff, is_active=True,
                 is_superuser=is_superuser, last_login=now,
                 date_joined=now, address=address, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user
    
      def create_user(self, username, email=None, password=None, **extra_fields):
        return self._create_user(username, email, password, False, False, True,
                     **extra_fields)
    
      def create_superuser(self, username, email, password, **extra_fields):
        user=self._create_user(username, email, password, True, True,
                     **extra_fields)
        user.is_active=True
        user.save(using=self._db)
        return user
    
    
    class User(AbstractBaseUser, PermissionsMixin):
      username = models.CharField(_('username'), max_length=30, unique=True,
        help_text=_('Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters'),
        validators=[
          validators.RegexValidator(re.compile('^[\w.@+-]+$'), _('Enter a valid username.'), _('invalid'))
        ])
      first_name = models.CharField(_('first name'), max_length=30, blank=True, null=True)
      last_name = models.CharField(_('last name'), max_length=30, blank=True, null=True)
      email = models.EmailField(_('email address'), max_length=255, unique=True)
      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)
      receive_newsletter = models.BooleanField(_('receive newsletter'), default=False)
      birth_date = models.DateField(_('birth date'), auto_now=False, null=True)
      address = models.CharField(_('address'), max_length=30, blank=True, null=True)
      phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
      phone_number = models.CharField(_('phone number'), validators=[phone_regex], max_length=30, blank=True, null=True) # validators should be a list
    
      USER_TYPES = (
        ('Farmer', 'Farmer'),
        ('Windmill owner', 'Windmill owner'),
        ('Solar panel owner', 'Solar panel owner'),)
      user_type = models.CharField(_('user type'), choices=USER_TYPES, max_length=30, blank=True, null=True)
    
      USERNAME_FIELD = 'username'
      REQUIRED_FIELDS = ['email',]
    
      objects = UserManager()
    
      class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
    
      def get_full_name(self):
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()
    
      def get_short_name(self):
        return self.first_name
    
      def email_user(self, subject, message, from_email=None):
        send_mail(subject, message, from_email, [self.email]) 
    

    有什么问题?

2 个答案:

答案 0 :(得分:12)

似乎django-allauth默认不允许保存自定义字段:

(参考:https://github.com/pennersr/django-allauth/blob/master/allauth/account/adapter.py#L227

要解决此问题,只需在执行user.save()

之前指定自定义字段值
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
setup_user_email(request, user, [])

user.address = self.cleaned_data.get('address')
user.user_type = self.cleaned_data.get('user_type')

user.save()
return user

这是一个肮脏的修复。更简洁的方法是覆盖allauth适配器以支持您的自定义字段。

答案 1 :(得分:0)

要覆盖默认适配器并保存自定义字段,请尝试以下

在app根文件夹中创建adapters.py文件并粘贴下面的代码

from allauth.account.adapter import DefaultAccountAdapter


class CustomUserAccountAdapter(DefaultAccountAdapter):

    def save_user(self, request, user, form, commit=True):
        """
        Saves a new `User` instance using information provided in the
        signup form.
        """
        from allauth.account.utils import user_field

        user = super().save_user(request, user, form, False)
        user_field(user, 'address', request.data.get('address', ''))
        user_field(user, 'first_name', request.data.get('first_name', ''))
        user_field(user, 'last_name', request.data.get('last_name', ''))
        user_field(user, 'user_type', request.data.get('user_type', ''))
        user.save()
        return user

最后通过在settings.py文件中添加此行来设置设置配置以使用自定义适配器

ACCOUNT_ADAPTER = 'users.adapters.CustomUserAccountAdapter'