django-rest-auth自定义注册无法保存额外字段 [英] django-rest-auth custom registration fails to save extra fields
问题描述
- 我已定制的用户模型有额外的字段
- 我有自定义注册序列化程序来存储额外的注册一个新用户时,必须填写用户名,密码。
注册成功,但额外的字段不会与用户名first_name一起保存,last_name和密码。
我的模型:
class UserManager BaseUserManager)
def _create_user(self,username,email,password,is_staff,is_superuser,address,** extra_fields):
now = timezone.now()
如果没有用户名:
raise ValueError(_('给定的用户名必须设置'))
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_pas sword(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, ** extra_fields)
user = self._create_user(username,email,password,True,True,
** extra_fields)
user.is_active = True
user.save使用= self._db)
返回用户
类用户(AbstractBaseUser,PermissionsMixin):
username = models.CharField(_('username'),max_length = 30,unique = True,
help_text = _('必需) 30个字符以内。字母,数字和@ /。/ + / - / _字符'),
validators = [
validators.RegexValidator(re.compile('^ [\w。@ + - ] + $' ),_('输入有效的用户名'),_('无效')
])
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(_地址'),max_length = 255,unique = True)
is_staff = models.BooleanField(_('staff status'),default = False,
help_text = _('指定用户是否可以登录这个管理网站'))
is_active = models.BooleanField(_('active'),default = True,
help_text = _('指定该用户是否应该被视为活动的,取而代之删除帐号'))
date_joined = models.DateTimeField(_('date joined'),default = timezone.now)
receive_newsletter = models.BooleanField(_('receive newslet ter'),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 =电话号码必须输入格式为'+999999999'。最多可允许15位数字。)
phone_number = models.CharField(_('phone number'),validators = [phone_regex],max_length = 30,blank = True,null = True)#validators应该是一个列表
USER_TYPES =(
('Farmer','Farmer'),
('风车所有者','风车所有者'),
('太阳能电池板所有者','太阳能电池板所有者'),
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,消息,from_email =无):
send_mail(subject,message,from_email,[self.email])
我的序列化器:
class RegisterSerializer(serializers.Serializer):
email = serializers.EmailField(required = allauth_settings.EMAIL_REQUIRED)
first_name = serializers.CharField(required = True,write_only = True)
last_name = serializers.CharField(required = True,write_only = True)
address = serializers.CharField(required = True,write_only = True)
user_type = serializers.ChoiceField(
choices =(('Farmer','Farmer'),('Windmill owner','Windmill owner'),('太阳能电池板所有者'面板所有者'))
style = {'base_template':'radio.html'},
required = True,write_only = True
password1 = serializers.CharField(required = True,write_only = True)
password2 = serializers.CharField(required = True,write_only = True)
def validate_email(self,email):
email = get_adapter()。clean_email(email)
如果allauth_settings.UNIQUE_EMAIL:
如果电子邮件和email_address_exists(电子邮件):
raise serializers.ValidationError(
_(A user is已经在此电子邮件地址注册。)
返回电子邮件
def validate_password1(self,password):
return get_adapter()。clean_password(password)
def validate(self,data):
如果data ['password1']!= data ['password2']:
raise serializers.ValidationError(
_两个密码字段不匹配。))
返回数据
def get_cleaned_data(self):
return {
'first_name':self.validated_data.get ('first_name',''),
'last_name':self.validated_data.get('last_name',''),
'address':self.validated_data.get('address',' ),
'user_type':self.validated_data.get('user_type',''),
'password1':self.validated_data.get('password1',''),
'email ':self.validated_data.get('email',''),
}
def save(self,request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request,user,self)
setup_user_email(request,user,[])
user.save()
返回用户
错误?
似乎django-allauth不允许默认保存自定义字段:
(ref: https://github.com/pennersr/django-allauth/blob/master/allauth/acco unt / adapter.py#L227 )
要解决这个问题,只需在执行 user.save之前分配自定义字段值( )
self.cleaned_data = self.get_cleaned_data()
adapter.save_user ,user,self)
setup_user_email(request,user,[])
user.address = self.cleaned_data.get('address')
user.user_type = self。 clean_data.get('user_type')
user.save()
返回用户
这是一个脏的修复。更清洁的方法是覆盖allauth适配器以支持您的自定义字段。
I am using DRF and for login/registration I am using Django-rest-auth.
- I have customized User model to have extra fields
- I have custom registration serializer to store extra fields along with username, password while registering a new user.
Registration is successful however, extra fields are not saved along with username, first_name, last_name and password.
My model:
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])
My Serializer:
class RegisterSerializer(serializers.Serializer):
email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
first_name = serializers.CharField(required=True, write_only=True)
last_name = serializers.CharField(required=True, write_only=True)
address = serializers.CharField(required=True, write_only=True)
user_type = serializers.ChoiceField(
choices=(('Farmer', 'Farmer'),('Windmill owner', 'Windmill owner'),('Solar panel owner', 'Solar panel owner'),),
style={'base_template': 'radio.html'},
required=True, write_only=True)
password1 = serializers.CharField(required=True, write_only=True)
password2 = serializers.CharField(required=True, write_only=True)
def validate_email(self, email):
email = get_adapter().clean_email(email)
if allauth_settings.UNIQUE_EMAIL:
if email and email_address_exists(email):
raise serializers.ValidationError(
_("A user is already registered with this e-mail address."))
return email
def validate_password1(self, password):
return get_adapter().clean_password(password)
def validate(self, data):
if data['password1'] != data['password2']:
raise serializers.ValidationError(
_("The two password fields didn't match."))
return data
def get_cleaned_data(self):
return {
'first_name': self.validated_data.get('first_name', ''),
'last_name': self.validated_data.get('last_name', ''),
'address': self.validated_data.get('address', ''),
'user_type': self.validated_data.get('user_type', ''),
'password1': self.validated_data.get('password1', ''),
'email': self.validated_data.get('email', ''),
}
def save(self, request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
setup_user_email(request, user, [])
user.save()
return user
What is wrong?
It seems like django-allauth doesn't allow saving custom fields by default:
(ref: https://github.com/pennersr/django-allauth/blob/master/allauth/account/adapter.py#L227)
To go around it, simply assign the custom field values before doing 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
That was a dirty fix. A cleaner way would be to override the allauth adapter to support your custom fields.
这篇关于django-rest-auth自定义注册无法保存额外字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!