Django中使用Form而非ModelForm填充表单实现资料编辑
解决方案:用Form实现用户资料填充与编辑
因为你使用的是forms.Form而非ModelForm,无法通过instance参数绑定模型实例,所以需要通过**initial参数填充现有用户数据**,并在表单验证通过后手动更新用户模型。下面是具体修改步骤:
1. 调整CustomerForm适配编辑场景
编辑资料时用户可能不需要修改密码,先把密码字段设为非必填,同时调整验证逻辑,只有当用户输入密码时才校验一致性:
# forms.py from django import forms from django.contrib.auth.validators import validate_username from django.core.validators import validate_email from django.core.exceptions import ValidationError class CustomerForm(forms.Form): username = forms.CharField(label='Desired Username', max_length=150, validators=[validate_username]) first_name = forms.CharField(label='First Name', max_length=150) last_name = forms.CharField(label='Last Name', max_length=150) email = forms.EmailField(label='Your Email', validators=[validate_email]) # 编辑时密码可选,设为非必填 password1 = forms.CharField(label='Enter Password', widget=forms.PasswordInput, min_length=8, required=False) password2 = forms.CharField(label='Retype Password', widget=forms.PasswordInput, min_length=8, required=False) def clean(self): cleaned_data = super().clean() password1 = cleaned_data.get("password1") password2 = cleaned_data.get("password2") # 只有当两个密码字段都有值时才校验匹配 if password1 or password2: if password1 != password2: raise ValidationError("Passwords do not match") return cleaned_data
2. 修改edit_profile视图,用initial填充表单
GET请求时,把当前用户的字段值传入表单的initial参数来填充表单;POST请求时,验证表单后手动更新User实例:
# views.py from django.shortcuts import render, redirect from django.contrib.auth import login, get_user_model from django.http import HttpResponse from .forms import CustomerForm User = get_user_model() """Function for editing profile.""" def edit_profile(request): # 直接用request.user获取当前登录用户,比session更安全 profile = request.user if request.method == 'POST': form = CustomerForm(request.POST) if form.is_valid(): # 手动更新用户字段 profile.username = form.cleaned_data['username'] profile.first_name = form.cleaned_data['first_name'] profile.last_name = form.cleaned_data['last_name'] profile.email = form.cleaned_data['email'] # 如果用户输入了密码,才更新密码 if form.cleaned_data['password1']: profile.set_password(form.cleaned_data['password1']) profile.save() return redirect('../book/') else: return render(request, 'edit.html', {'form': form}) # GET请求时,用initial填充现有用户数据 initial_data = { 'username': profile.username, 'first_name': profile.first_name, 'last_name': profile.last_name, 'email': profile.email, # 密码字段留空,避免显示明文或哈希值 } form = CustomerForm(initial=initial_data) return render(request, 'edit.html', {'form': form})
3. 优化原代码的小问题
- 原
sign_up视图里用request.session['normal_username']没必要,登录后直接用request.user即可 - 异常处理别用宽泛的
Exception,可以捕获具体异常比如IntegrityError(用户名/邮箱重复),给用户更明确的提示:
# 优化后的sign_up视图 from django.db import IntegrityError """Function for sign up.""" def sign_up(request): if request.method == 'POST': form = CustomerForm(request.POST) if form.is_valid(): try: user = User.objects.create_user( username=form.cleaned_data['username'], email=form.cleaned_data['email'], password=form.cleaned_data['password1'] ) user.first_name = form.cleaned_data['first_name'] user.last_name = form.cleaned_data['last_name'] user.save() login(request, user) return redirect('../book/') except IntegrityError: form.add_error('username', 'This username is already taken.') return render(request, 'sign_up.html', {'form': form}) return render(request, 'sign_up.html', {'form': form}) return render(request, 'sign_up.html', {'form': CustomerForm()})
内容的提问来源于stack exchange,提问作者Anshul Gupta
相关产品推荐
相关产品推荐

