Django自定义用户模型注册后phone字段被错误填充为姓名
问题描述
Django应用注册视图提交表单后,用户能成功保存,但phone字段被填充为first_name与last_name的组合。表单可正确验证手机号,但数据库中phone字段存储无效内容。手动调用AvitoUser.objects.create_user('Hello', 'World', '79531323301', 'somepassword')功能正常,但使用类视图或函数视图均出现该问题。
相关代码
models.py
from django.contrib.auth.models import AbstractUser from django.db import models from django.utils.translation import gettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField from django.urls import reverse from .managers import CustomUserManager class AvitoUser(AbstractUser): username = None first_name = models.CharField(max_length=16) last_name = models.CharField(max_length=16) phone = PhoneNumberField(_("phone number"), unique=True) USERNAME_FIELD = "phone" REQUIRED_FIELDS = ["first_name", "last_name"] objects = CustomUserManager() def get_username(self): return f'{self.first_name} {self.last_name}' def get_absolute_url(self): return reverse('users:profile', kwargs={'pk': self.id}) def __str__(self): return f'AvitoUser№ {self.id} , f-s name: {self.first_name} {self.last_name}'
forms.py
from django import forms from django.contrib.auth.forms import UserCreationForm from phonenumber_field.formfields import PhoneNumberField from django.contrib.auth import get_user_model AvitoUser = get_user_model() class RegisterForm(UserCreationForm): first_name = forms.CharField(label='First name', max_length=16) last_name = forms.CharField(label='Last name', max_length=16) phone = PhoneNumberField() class Meta: model = AvitoUser fields = ["first_name", "last_name", "phone", "password1", "password2",]
views.py(类视图)
from django.views import generic from django.urls import reverse_lazy from django.contrib.auth import get_user_model from . import forms AvitoUser = get_user_model() ... class SignupView(generic.CreateView): model = AvitoUser form_class = forms.RegisterForm success_url = reverse_lazy('users:login') template_name = "registration/signup.html" ...
registration/signup.html
{% extends 'base_generic.html' %} {% block content %} <form method="POST" class="form-group"> {% csrf_token %} {{ form.as_p }} <button type="submit" class="btn btn-success">Register</button> </form> {% endblock %}
managers.py
from django.contrib.auth.base_user import BaseUserManager from django.utils.translation import gettext_lazy as _ class CustomUserManager(BaseUserManager): """ Custom user model manager where phone is the unique identifiers for authentication instead of usernames. """ def create_user(self,first_name, second_name, phone, password, **extra_fields): """ Create and save a user with the given phone and password. """ if not phone: raise ValueError(_("The phone must be set")) user = self.model(first_name=first_name, second_name=second_name, phone=phone, **extra_fields) user.set_password(password) user.save() return user
views.py(函数视图)
def register(request): if request.method == 'POST': user_form = forms.RegisterForm(request.POST) if user_form.is_valid(): new_user = user_form.save(commit=False) new_user.set_password(user_form.cleaned_data['password2']) new_user.save() return redirect(reverse_lazy('users:profile', kwargs={'pk': new_user.id})) else: user_form = forms.RegisterForm() return render(request, 'registration/signup.html', {'form': user_form})
解决方案
1. 修正get_username()方法的返回值
由于AvitoUser的USERNAME_FIELD被设置为phone,按照Django约定,get_username()方法应该返回phone字段的值,而非姓名组合。错误的返回值会导致内部逻辑混乱,进而覆盖phone字段内容。
修改models.py中的get_username():
def get_username(self): return str(self.phone) # 返回phone字段的字符串形式
2. 修复用户管理器的字段映射错误
CustomUserManager.create_user方法中,参数second_name与模型字段last_name不匹配,创建用户实例时的字段赋值也存在错误,导致参数传递混乱。
修改managers.py中的create_user方法:
def create_user(self, first_name, last_name, phone, password, **extra_fields): """ Create and save a user with the given phone and password. """ if not phone: raise ValueError(_("The phone must be set")) # 修正字段名:将second_name改为last_name,匹配模型字段 user = self.model(first_name=first_name, last_name=last_name, phone=phone, **extra_fields) user.set_password(password) user.save() return user
3. 验证表单逻辑
RegisterForm已正确使用PhoneNumberField验证手机号,且字段映射正确,无需额外修改。
完成上述修改后,重新测试注册功能,phone字段将正确存储用户输入的手机号。
内容的提问来源于stack exchange,提问作者Artem
相关产品推荐
相关产品推荐

