forms组件的基本使用与结合ajax提交数据

用Ajax提交用户的注册信息(用户名,密码,确认密码,年龄),提交的数据格式为json。用form组件做认证和数据校验,姓名要大于4位,小于16位,并且不能以sb开头和结尾,用户名如果存在,返回用户存在;密码(最大16位,最小8位);年龄,大于18岁,小于100岁,密码和确认密码一致,校验不通过返回错误信息,校验通过,存到user表中。

# 前端代码
<form id="myform">
{% csrf_token %}
{% for userinfo in myforms_obj %}
    <p>
        <lable for="{{ form.auto_id }}">{{ userinfo.label }}</lable>
        <span>{{ userinfo }}</span>
    <span style="color: red"></span>
    </p>
{% endfor %}
</form>
<input type="button" class="btn btn-primary pull-right" value="注册" id="id_commit">
</body>
<script>
    $('#id_commit').click(function () {
        // 通过属性选择器选择到性别value
        let gender_Val = $(':checked').val()
        console.log(gender_Val)
        // 3.发送ajax请求
        $.ajax({
            url: "",
            type: 'post',
            headers: {'X-CSRFToken': $('input[name=csrfmiddlewaretoken]').val()},
            data: JSON.stringify({
                'username': $('#id_username').val(),
                'age': $('#id_age').val(),
                'password': $('#id_password').val(),
                'confirm_pwd': $('#id_confirm_pwd').val(),
                'gender': gender_Val
            }),
            // 指定数据格式为json
            contentType: 'application/json',
            success: function (args) {
                if (args.code == 1000) {

                    alert('提交成功')
                    // 跳转到url指定页面
                    window.location.href = args.url
                } else {
                    // 如何将对应的错误提示展示到对应的input框下面
                    // forms组件渲染的标签的id值都是 id_字段名
                    $.each(args.msg, function (index, obj) {
                        console.log(index, obj)  //  username        ["用户名不能为空"]
                        let targetId = '#id_' + index;
                        $(targetId).parent().next().text(obj[0])  // 查找错误信息标签
                    })
                }
            }
        })
    })
</script>
# views代码
class Validator(forms.Form):
    username = forms.CharField(max_length=16, min_length=4, label='用户名',
                               error_messages={
                                   'max_length': '用户名过长',
                                   'min_length': '用户名过短',
                                   'required': '请输入用户名'
                               },
                               # widget=widgets.TextInput(attrs={"class": "form-control"})
                               )
    age = forms.IntegerField(label='年龄',
                             error_messages={'required': '请输入年龄后提交'},
                             # widget=widgets.TextInput(attrs={"class": "form-control"})
                             )
    password = forms.CharField(max_length=16, min_length=8, label='密码',
                               error_messages={
                                   'max_length': '密码名过长',
                                   'min_length': '密码至少八位',
                                   'required': '请确认密码'
                               },
                               # widget=widgets.PasswordInput(attrs={"class": "form-control"})
                               )
    confirm_pwd = forms.CharField(max_length=16, min_length=8, label='确认密码',
                                  error_messages={
                                      'max_length': '密码名过长',
                                      'min_length': '密码至少八位',
                                      'required': '请确认密码'
                                  },
                                  # widget=widgets.PasswordInput(attrs={"class": "form-control"})
                                  )
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

    # 局部钩子
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if 'sb' in username:
            self.add_error('username', '含有sb是不可以的')
        user_obj = models.UserInfo.objects.filter(username=username).first()
        if user_obj:
            self.add_error('username', '这个用户已经存在')
        return username

    # 全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_pwd')
        if not password == confirm_password:
            self.add_error('confirm_pwd', '2次密码输入不一致!')
        age = self.cleaned_data.get('age')
        if not age in range(18,100):
            self.add_error('age', '年龄在18岁到100岁之间')
        return self.cleaned_data


from app01 import models
from django.http import JsonResponse
import json
# 信息认证保存
def validator(request):
    back_dic = {'code': '', 'msg': ''}
    myforms_obj = Validator()
    if request.method == 'POST':
        data = json.loads(request.body)
        myforms_obj = Validator(data)
        if myforms_obj.is_valid():
            data = myforms_obj.cleaned_data
            data.pop('confirm_pwd')
            back_dic['code'] = 1000
            back_dic['url'] = 'http://www.baidu.com'
            models.UserInfo.objects.create(**data)
        else:
            back_dic['code'] = 2000
            back_dic['msg'] = myforms_obj.errors
        return JsonResponse(back_dic)
    return render(request, 'validator.html', locals())

# models模块
class UserInfo(models.Model):
    username = models.CharField(max_length=16,verbose_name='用户名')
    password = models.CharField(max_length=16,verbose_name='密码')
    age = models.IntegerField(default=18)
    gender_choice = ((1,'男'),(2,'女'),(3,'保密'))
    gender = models.IntegerField(verbose_name='性别',choices=gender_choice,default=1)
# forms组件的使用流程
 导入forms模块和widgets模块:from django import forms    from django.forms import widgets
 利用form.需要生成的字段名  生成字段forms字段
 前端渲染,需要在后端views当中生成一个forms空对象,用于渲染出页面,这里提前可以定义好错误信息怎么渲染,注意错误信息的提示是errors.0,因为返回的错误信息是一个列表
 对于默认的校验规则不满足使用要求,可以使用全局钩子(clean)和局部钩子(clean_校验字段名)去自定义校验规则,将错误信息添加到错误的容器当中。

# 对于需要注意的点:
        1. 需要传递json数据的时候,修改数据编码格式: contentType: 'application/json',传递的数据也放在了request.body当中;
        2.如果有文件对象,可以借助Formdata对象进行传递;
        3.csrf_token的值可以放在头当中;
        4.传递到后端的数据需要用json模块反序列化得到字典数据进行校验;
        5.对于钩子函数,局部钩子函数是将勾出来的数据进行返回;全局钩子函数是返回self.cleaned_data
        
 对于forms组件的常用字段请查看博文:https://www.cnblogs.com/Ailewent/articles/14218728.html,个人总结,总结不到位的地方请多多指教
原文地址:https://www.cnblogs.com/Ailewent/p/14338838.html