前后端传输编码格式

form表单在传输编码格式有两种: 1.urlencoded,2 multipart/form-data

在不指定编码的情况下,默认使用urlencoded,他只能传输文本格式的信息,如果传文件的话只能传文件的名称过去。并不能传输文件内容过去,使用form表单同时提交文本和文件也是可以的,我们将编码格式转为 multipart/form-data

就可以实现同时传输文本,和文件

<form action="" method="post" enctype="multipart/form-data">

form表单和ajax支持的编码格式有两个是相同的,两者都支持urlencoded和form-data,在Ajax中还支持json编码格式:

Ajax传输数据:

Ajax发送json格式数据
     $.ajax({
            url:'',  // 不写默认朝当前页面所在的url地址提交
            type:'post',
            contentType:'application/json',
            data:JSON.stringify({'name':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}),
            success:function (data) {
                alert(data)
            }
        })

后台代码:

def index(request):
    bytes_str = request.body
    res = json.loads(bytes_str.decode('utf-8'))
    print(res)
    return  render(request,'index.html')

ajax同时传输数据和文件:

    $('#d1').click(function () {
        // 如果用ajax发送文件 需要使用内置对象FormData
        var formData = new FormData();  // 生成一个内置对象
        // 内置对象formdata既可以传普通的键值对,也可以传文件
        formData.append('name','jason');  // 普通键值对
        formData.append('password','123');
        // 传文件
        var fileObj = $('#d2')[0].files[0];  // 先获取标签对象 转成原生js对象 通过内置的files方法拿到列表 然后去索引0拿到文件对象
        formData.append('myfile',fileObj);
        $.ajax({
            url:'',  // 不写默认朝当前页面所在的url地址提交
            type:'post',
            // 注意ajax在发送文件的时候 需要你手动指定两个特殊的参数
            contentType:false,  // 不要用任何编码 使用我formdata自带的编码即可
            processData:false,  // 浏览器不要处理我的数据 是什么就什么
            data:formData,
            success:function (data) {
                alert(data)
            }

        })
    })

后台代码:

def index(request):
    if request.method == 'POST':
        print(request.POST)
        print(request.FILES)
        file_obj = request.FILES.get('myfile')
        with open(file_obj.name,'wb') as f:
            for line in file_obj:
                f.write(line)
    return render(request,'index.html')

form组件

form组件主要是帮助我们完成三件事:1 校验前台数据 2 渲染前台页面给用户提供输入条件 3  将数据处理后的结果展示给用户看

用form组件写用户注册。

1 导入模块包    

from django import forms

创建form组件模型表

class MyForm(forms.Form):
    name = forms.CharField(max_length=6,label='用户名',
                           error_messages = {'max_length':'用户名最大6位','required':'用户名不能为空'})
    password = forms.CharField(max_length=8,min_length=3,label='密码',
                               error_messages={'max_length':'密码最大为8位',"min_length":'密码最少为3位','required':'密码不能为空'})
    confirm_password = forms.CharField(max_length=8,min_length=3,label='再次确认密码',
                                       error_messages={'min_length':'密码最少3位','required': "密码不能为空"} )
    def clean_name(self):
        name = self.cleaned_data.get('name')
        if 'sb' in name:
            self.add_error('name','用户名不能包含敏感词汇')
        return name

    def clean(self):
        password = self.cleaned_data.get('password')
        print(password)
        confirm_password = self.cleaned_data.get('confirm_password')
        print(confirm_password)
        if not password == confirm_password:
            self.add_error('confirm_password','两次密码不一致')
        return self.cleaned_data

其中两个函数方式用的钩子函数,可以在后台做前台用户输入信息的判断,数据校验对于前台来说,可以做也可以不做,后台是一定要做的,使用钩子函数可以实现这个需求。

注册函数,前台得到的数据我们可以直接使用request.post直接作为参数传进去,因为form组件模型表有一个特点,参数少传了不行,多的参数也不会进行校验:

def register(request):
    form_obj = MyForm()
    if request.method == 'POST':
        form_obj = MyForm(request.POST)
        if form_obj.is_valid():
            print(form_obj.cleaned_data)
            return HttpResponse('注册成功')
    return render(request,'register.html',{"form_obj":form_obj})

前台页面渲染方式

方式1 缺点是封装的程度太高了,不方便以后扩展 :

{#    {{ form_obj.as_p }}#}
{#    {{ form_obj.as_ul }}#}

方式2 优点是可扩展性高,但是书写起来太麻烦 

   <p>
        {{ form_obj.username.label }}{{ form_obj.username }}  {# forms对象点字段名拿到的是对应的输入框 
        </p>
        <p>
            {{ form_obj.password.label }}{{ form_obj.password }}  {# forms对象点字段名拿到的是对应的输入框 
        </p>

方式3 利用循环遍历通过对象点方法渲染前台页面,这种方法比较常用 :

  {% for foo in form_obj %}
        <P>
            {{foo.label}}:{{foo}}
            <span>{{foo.errors.0}}</span>
        </P>
    {% endfor %}

当我们需要测试在本地测试时可以打开一个新的test.py文件,配置好文件后导入我们想要测试的模块即可。‘

    django中测试脚本书写
    import os
    import sys

    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day66.settings")
        import django
        django.setup()
          
        from app01 import models
        print(models.Userinfo.objects.all())

钩子函数可以分为两种局部钩子函数,全局钩子函数:

局部对应的某个字段,而全局钩子对应的是全局中的所有字段:

局部钩子:

   def clean_name(self):
        name = self.cleaned_data.get('name')
        if 'sb' in name:
            self.add_error('name','用户名不能包含敏感词汇')
        return name

全局钩子函数:

    def clean(self):
        password = self.cleaned_data.get('password')
        print(password)
        confirm_password = self.cleaned_data.get('confirm_password')
        print(confirm_password)
        if not password == confirm_password:
            self.add_error('confirm_password','两次密码不一致')
        return self.cleaned_data

在form组件中,我们可以通过一些方法,来查看用户输入的数据是否合法,哪些合法,哪些不合法以及报错原因:

3.查看数据是否完全合法
                obj.is_valid()
            4.查看所有校验通过的数据
                obj.cleaned_data
                {'email': '123@qq.com'}
            5.查看所有没有通过的数据
                obj.errors
                """
                {
                    'username': ['Ensure this value has at most 6 characters (it has 7).'], 
                    'password': ['Ensure this value has at least 3 characters (it has 2).']}
                """
原文地址:https://www.cnblogs.com/1624413646hxy/p/11229074.html