关于django表单ModelForm保存问题

需求:实现django用户注册功能

问题分析:Django提供了一个后台管理系统,注册用户可以通过后台管理系统轻松实现。但我们需要实现的用户注册功能是针对于用户的,总不可能让用户登录后台系统自行添加自己的信息吧。Django中储存用户信息的数据表是auth_user,所以我们只需要将用户提供的表单信息保存进auth_user就实现了用户的自行注册。

首次尝试:
1、新增表单类,在form.py文件下填写一下代码:

from django.contrib.auth.models import User

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ["username","password","first_name","last_name","email"]

``User是auth_user表的模型

2、在view.py文件下编写表单处理逻辑,由于Django的用户密码是进行加密后再写入数据库的,在保存进数据库之前,必须对密码进行加密处理。调佣方法is_valid()后,FormModel对象会生成cleaned_data,起初以为调用save()方法是根据生成的cleaned_data进行保存,所以在save前修改cleaned_data达到目的

from django.shortcuts import render, redirect
from django.contrib.auth.hashers import make_password
from .forms import UserForm

def signup(request):
    
    form = UserForm()
    if request.method == "POST":
        form = UserForm(request.POST)
        if form.is_valid():
            form.cleaned_data["password"] = make_password(form.cleaned_data.get("password"))
            form.save()
            return redirect('restaurant-list')
        else:
            return HttpResponse("字段无效")
    context = {
        "form": form,
    }


    return render(request, 'signup.html', context)

make_password()可以对字符串进行加密,返回加密后的字符串,
如果需要对加密方式进行替换,可在setting.py中进行配置,默认使用第一种加密方式:

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]

三、提交表单验证结果

数据表查询结果

前两条信息是通过admin后台添加的用户,可以发现是成功进行了加密的,但是通过用户端添加注册的用户密码并没有进行加密。所以可以判断我们的思路是错误的,在save前对cleaned_data进行修改并不能影响结果。因此开始单步调试。

四、调试

调试代码片段
在此处发现cleaned_data的赋值方法,于是就想着在此处修改cleaned_data,看能否达到我们的目的。在之前的UserForm类(form.py)中加入clean_password方法,代码如下:

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ["username","password","first_name","last_name","email"]


    def clean_password(self):
        value = make_password(self.data.get("password"))
        return value

再次请求表单:
表单内容
数据表查询结果
可以发现密码正常进行了加密后存入了数据库,此处又产生了一些一个疑问:为什么在_clean_fields()(即form.is_vaild)方法中修改cleaned_data后写入数据库的就是加密后的密码,而在其之后便不行呢?首先想到的是,在save中数据的依据肯定不是cleaned_data,这点是肯定的,那么只有可能是在form.is_vaild()中将cleaned_data的值赋值给了另一个变量,而save方法就是通过这个变量的值对数据库进行写入,所以form.is_vaild()结束后,我们再对cleaned_data进行修改不会影响到后面的结果。带着疑问和初步的分析,我们继续调试。

调试代码片段
在此处可以发现model通过clean改变了属性的值,深入调试发下这里即是form.cleaned_data的值。由于ModelForm实例化时可以传入Instance参数(Model实例对象),进而于Model实例对象关联,所以我们可以猜测,FormModel的save方法是对instance(Model实例对象)的保存。接下来在save前修改form.instance,看是否能得到加密后的密码。代码如下:

def signup(request):
    
    form = UserForm()
    if request.method == "POST":
        form = UserForm(request.POST)
        if form.is_valid():
            form.instance.password = make_password(form.instance.password)
            #form.cleaned_data["password"] = make_password(form.cleaned_data.get("password"))
            form.save()
            return redirect('restaurant-list')
        else:
            return HttpResponse("字段无效")
    context = {
        "form": form,
    }

提交表单查看结果

数据库查询结果

可以看到,密码进行了加密后写入了数据库,这正是我们想要的结果。

综上,我们有两种解决方法:

第一种:在UserForm中写clean_password方法,对password进行处理。

第二种:在save 前更改form.instance.password,对其进行加密处理。

总结:保存的本质的在于对form.instance的更改,个人比较倾向第一种方法,因为是根据源代码的逻辑写入的方法,与Django模块有比较好的融合度。第二种的话可能会出现一些问题,比如password通过了form.is_vaild的检查,但是后期自己自行进行处理后,得到的加密password可能会不符合passwordField的要求,赋值时可能就会报错。我们还可以在request.POST中直接对表单数据进行处理,但同样会出现的问题,所以这里不推荐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值