You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:52:08