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

Django开发中注册表单无法添加额外自定义字段问题求助

核心问题说明

你当前代码的核心错误有3个:

  1. 重复在UserInfo扩展表定义了Django内置User模型已有的username/email/password字段,完全没有关联创建内置User实例,后续无法使用Django自带的登录、权限校验体系
  2. 密码直接明文存储,没有做哈希加密,存在严重安全隐患,confirm_password属于表单校验字段,根本不需要存入数据库
  3. 视图逻辑没有处理用户和扩展信息的关联创建,文件上传字段也没做对应配置,就算表单提交成功也没法正常使用
分步修正方案

1. 修正models.py

删掉UserInfo里和内置User表重复的字段,只保留扩展属性,调整后代码如下:

import uuid
from django.db import models
from django.contrib.auth.models import User

class UserInfo(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
    full_name = models.CharField(max_length=200, null=True, blank=True)
    profile_photo = models.ImageField(null=True, blank=True, upload_to='profile_photo/', default='profile_photo/default.jpg')
    phone_number = models.CharField(max_length=10, null=True, blank=True)
    address = models.TextField(null=True, blank=True)
    pin_code = models.CharField(null=True, max_length=6, blank=True)
    region = models.CharField(null=True, max_length=200, blank=True)
    state = models.CharField(null=True, max_length=100, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)

    def __str__(self):
        return str(self.user.username)

改完记得执行python manage.py makemigrations和python manage.py migrate同步数据库结构。

2. 重写forms.py

继承Django自带的UserCreationForm扩展自定义字段,内置的UserCreationForm已经帮你做好了密码一致性校验、密码加密的基础逻辑,你只需要把扩展字段加上即可,调整后代码:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import UserInfo

class RegisterForm(UserCreationForm):
    # 扩展User表需要的字段,自带的password1、password2UserCreationForm已经提供,对应密码和确认密码
    email = forms.EmailField(required=True, widget=forms.EmailInput(attrs={'class':'register-textinput2 input'}))
    
    class Meta:
        model = User
        # 先指定User表需要的字段
        fields = ['username', 'email', 'password1', 'password2']
        # 给User表的字段加样式
        widgets = {
            'username': forms.TextInput(attrs={'class':'register-textinput1 input'}),
        }

    # 给UserInfo的扩展字段加表单控件和样式
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['password1'].widget.attrs.update({'class': 'password-field-textinput input', 'id': 'passwordField'})
        self.fields['password2'].widget.attrs.update({'class': 'password-field-textinput input', 'id': 'cPasswordField'})
        # 追加扩展字段
        self.fields['full_name'] = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'class':'register-textinput input'}))
        self.fields['phone_number'] = forms.CharField(max_length=10, widget=forms.TextInput(attrs={'class': 'register-textinput3 input'}))
        self.fields['state'] = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class': 'register-textinput5 input'}))
        self.fields['region'] = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'class': 'register-textinput6 input'}))
        self.fields['address'] = forms.CharField(widget=forms.TextInput(attrs={'class': 'register-textinput7 input'}))
        self.fields['pin_code'] = forms.CharField(max_length=6, widget=forms.TextInput(attrs={'class': 'register-textinput8 input'}))
        self.fields['profile_photo'] = forms.ImageField(required=False)

    def save(self, commit=True):
        user = super().save(commit=False)
        user.email = self.cleaned_data['email']
        user.username = self.cleaned_data['username'].lower()
        if commit:
            user.save()
            # 保存关联的UserInfo扩展信息
            user_info = UserInfo.objects.create(
                user=user,
                full_name = self.cleaned_data['full_name'],
                phone_number = self.cleaned_data['phone_number'],
                state = self.cleaned_data['state'],
                region = self.cleaned_data['region'],
                address = self.cleaned_data['address'],
                pin_code = self.cleaned_data['pin_code'],
                profile_photo = self.cleaned_data.get('profile_photo')
            )
        return user

3. 修正views.py逻辑

补全文件上传参数,注册成功后增加跳转逻辑,调整后代码:

from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import RegisterForm

def register(request):
    form = RegisterForm()
    if request.method == "POST":
        # 接收POST参数和上传的文件
        form = RegisterForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            messages.success(request, "用户注册成功,请登录")
            # 注册成功跳转到登录页,避免重复提交
            return redirect('login')
    context = {'form': form}
    return render(request, 'user/register.html', context)

4. 调整HTML模板

表单标签加文件上传必须的编码属性,调整后代码:

<div>
<div class="register-container">
  <div class="header-container">
    <h1 class="header-text heading"><span>register</span></h1>
  </div>
  <div class="register-container01">
    <!-- 上传文件必须加enctype属性 -->
    <form method="POST" enctype="multipart/form-data">
      {% csrf_token %}
      {{form.as_p}}
      <input type="submit" value="submit">
    </form>
    <div class="register-container19">
      <a href="{% url 'login' %}" class="register-navlink imp">
        <span>我已有账号,去登录</span>
      </a>
    </div>
  </div>
</div>
注意事项
  • 不要在扩展表重复存储内置User表已有的认证相关字段,否则会出现数据不同步,Django自带的auth登录、权限校验功能全部无法正常使用
  • 绝对不能明文存储用户密码,Django自带的UserCreationForm已经内置了密码加盐哈希逻辑,不要自己写密码存储逻辑
  • 只要表单包含文件/图片上传字段,form标签必须加enctype="multipart/form-data"属性,否则后端接收不到上传的文件

内容的提问来源于stack exchange,提问作者Roshan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 05:01:05