Django框架进阶6 多对多三种创建方式, Ajax, Content-Type前后端传输数据编码格式, Ajax发送文件数据, django内置的序列化功能, Ajax结合sweetalert实

Posted 战斗小人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django框架进阶6 多对多三种创建方式, Ajax, Content-Type前后端传输数据编码格式, Ajax发送文件数据, django内置的序列化功能, Ajax结合sweetalert实相关的知识,希望对你有一定的参考价值。

多对多三种创建方式

1.全自动(较为常用)

    class Book(models.Model):
        title = models.CharField(max_length=32)
        authors = models.ManyToManyField(to=\'Author\')
        # orm就会自动帮你创建第三张表
        
    class Author(models.Model):
        name = models.CharField(max_length=32)
        
    \'\'\'
    好处:第三张表自己创建
    不足之处:第三张表无法扩展额外的字段
    \'\'\'

2.纯手动(了解)

    class Book(models.Model):
        title = models.CharField(max_length=32)

    class Author(models.Model):
        name = models.CharField(max_length=32)

    class Book2Author(models.Model):
        book = models.ForeignKey(to=\'Book\')
        author = models.ForeignKey(to=\'Author\')
        create_time = models.DateField(auto_now_add=True)
    
        """
        好处在于第三表可以扩展额外的字段
        不足之处:orm查询的时候会带来不便
        """            

3.半自动(推荐)

    class Book(models.Model):
        title = models.CharField(max_length=32)
        authors = models.ManyToManyField(to=\'Author\', through=\'Book2Author\', through_fields=(\'book\', \'author\'))


    class Author(models.Model):
        name = models.CharField(max_length=32)
        books = models.ManyToManyField(to=\'Author\', through=\'Book2Author\', through_fields=(\'author\', \'book\'))


    class Book2Author(models.Model):
        book = models.ForeignKey(to=\'Book\')
        author = models.ForeignKey(to=\'Author\')
        create_time = models.DateField(auto_now_add=True)


    """
    好处在于第三步可以扩展任意的额外字段 还可以利用orm 正反向查询
    不足之处:无法利用
        add
        set
        remove
        clear
    虽然无法使用了 但是你还可以自己直接操作第三表
    """

 

Ajax(异步提交、局部刷新)

同步与异步

同步  任务提交之后原地等待任务的返回结果  进程表现上来说  阻塞

异步  任务提交之后不需要原地等待返回结果  直接执行下一行代码  继承表现上来说  非阻塞任务的结果肯定是需要的  是通过异步回调机制  callback()

 

与后端进行交互的方式

1.浏览器窗口输入url回车    GET

2.a标签href属性填写url点击     GET

3.form表单          GET/POST

4.Ajax            GET/POST

 

Ajax并不是一门新的语言  它其实就是基于js写的一个功能模块而已

由于原生js书写ajax较为繁琐  所以我们直接学jQuery封装好的ajax模块操作

 

初识ajax

案例:页面上有三个input框  一个按钮

用户在前两个框中输入数字  点击按钮保证页面不刷新的情况下将数据发到后端做计算

将计算好的结果再发给前端展示到第三个input框中

ajax基本语法结构

// ajax基本语法
$.ajax({
    // 1.到底朝哪个后端提交数据
    url:\'\',  // 控制数据的提交路径  有三种写法 跟form表单的action属性一致
    // 2.指定当前请求方式
    type:\'post\',
    // 3.提交的数据
    data:{\'i1\':$(\'#i1\').val(),\'i2\':$(\'#i2\').val()},
    // 4.ajax是异步提交 所以需要给一个回调函数来处理返回的结果
    success:function (data) {  // data就是异步提交的返回结果
        // 将异步回调的结果通过DOM操作渲染到第三个input框中
        $(\'#i3\').val(data)
    }
})

例:

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3">
<button id="d1">按钮</button>

<script>
    $(\'#d1\').click(function () {
        // 获取两个框里面内容  朝后端提交异步请求
        // ajax基本语法
        $.ajax({
            // 1.到底朝那个后端提交数据
            url:\'\', // 控制数据的提交路径  有三种写法  跟form表单的action属性一样
            // 2.指定当前请求方式
            type:\'post\',
            // 3.提交的数据
            data:{\'i1\':$(\'#i1\').val(),\'i2\':$(\'#i2\').val()},
            // 4.ajax是异步提交  所以需要给一个回调函数来处理返回的结果
            success:function (data) {   // data就是异步提交的返回结果
                // 将异步回调的结果通过DOM操作渲染到第三个input框中
                $(\'#i3\').val(data)
            }
        })
    })
</script>
</body>
</html>

app01/views.py

from django.shortcuts import render,HttpResponse

def index(request):
    if request.method == \'POST\':
        i1 = request.POST.get(\'i1\')
        i2 = request.POST.get(\'i2\')
        # i1 和 i2 是字符串类型  需要先做类型转换
        i3 = int(i1) + int(i2)
        return HttpResponse(i3)
    return render(request,\'index.html\')

content-Type前后端传输数据的编码格式

  urlencoded
  formdata
  application/json

 

form表单

  默认是urlencoded编码格式传输数据

   urlencoded数据格式

      username=jason&password=123

      django后端针对该格式的数据  会自动解析并帮你打包到request.POST中

  formdata数据格式

      django后端针对符合urlencoded编码格式数据(普通键值对)还是统一解析到request.POST

      而针对formdata文件数据就会自动解析放到request.FILES

ajax提交

  ajax默认的也是urlencoded编码格式

    前后端数据交互   编码格式与数据格式一定要一致

  application/json

    django后端针对json格式数据  并不会做任何的处理

    因为没有人拿,数据就以二进制的形式存放在request.body中

$(\'#d2\').on(\'click\',function () {
    $.ajax({
            rl:\'\',
            type:\'post\',
            // 修改content-Type参数
            contentType:\'application/json\',
            data:JSON.stringify({\'username\':\'jason\',\'password\':123}),  // 将数据序列化成json格式字符串
            success:function (data) {
            alert(data)
            }
       })
})

例:

templates/ab_ct.html

<button id="d2">ajax发送json格式数据</button>
<script>
    $(\'#d2\').on(\'click\',function () {
        $.ajax({
            url:\'\',
            type:\'post\',
            // 修改content-Type参数
            contentType:\'application/json\',
            data:JSON.stringify({\'username\':\'jason\',\'password\':123}),   // 将数据序列化成JSON格式字符串
            success:function (data) {
                alert(data)
            }
        })
    })

</script>
View Code

app01/views.py

from django.shortcuts import render,HttpResponse
import json

def ab_ct(request):
    if request.method == \'POST\':
        # print(request.POST)
        # print(request.FILES)
        # print(request.body)
        #自己处理json格式数据
        json_bytes = request.body
        # 先解码
        # json_str = json_bytes.decode(\'utf8\')

        # 扩展 json.loads能够自动解码并序列化
        json_dict = json.loads(json_bytes)
        print(json_dict,type(json_dict))

    return render(request,\'ab_ct.html\')

 

ajax中dataType属性:

# 前端
$.ajax({ url:
\'\', # 控制后端提交路径 type:\'\', # 控制请求方式 data:{}, # 控制提交的数据 dataType:"JSON", # 有此句,django后端用HttpResponse返回json格式字符串,args会自动反序列化,拿到的是前端js的对象类型,而如果是用JsonResponse返回的那么args会自动返序列化成前端js的对象类型(如果此行不写,django后端用HttpResponse返回json格式字符串,args不会自动反序列化,拿到的还是json格式字符串string字符类型.如果是用JsonResponse返回,返回还是前端js的对象类型) success:function(args){ # 异步回调机制 }) # 后端 def index(request): if request.method == \'POST\': back_dic = {\'msg\':\'hahaha\'} return HttpResponse(json.dumps(back_dic)) # 需要加dataType:"JSON" return JsonResponse(back_dic) # 不需要 return render(request,\'index.html\') # 后续在写ajax请求的时候建议你加上dataType参数

 

ajax发送文件(******)

内置对象FormData

即发普通键值对也发文件

<input type="file" name="myfile" id="i1">
<button id="d3">ajax发送文件数据</button>
<script>
     $(\'#d3\').click(function () {
         // 1 需要先生成一个内置对象
            var myFormData = new FormData();
            // 2 传普通键值对  当普通键值对较多的时候 我们可以利用for循环来添加
            myFormData.append(\'username\',\'jason\');
            myFormData.append(\'password\',123);
            // 3 传文件
            myFormData.append(\'myfile\',$(\'#i1\')[0].files[0]);  // 获取input框内部用户上传的文件对象
            // 发送ajax请求
            $.ajax({
                url:\'\',
                type:\'post\',
                data:myFormData,
                // 发送formdata对象需要指定两个关键性的参数

                processData:false,  // 让浏览器不要对你的数据进行任何的操作
                contentType:false,  // 不要使用任何编码格式 对象formdata自带编码格式并且django能够识别该对象

                success:function (data) {
                    alert(data)
                }
            })
        })
</script>

 

序列化

django内置序列化组件

  接口文档 表名该大字典内都有哪些键值对

from django.shortcuts import render,HttpResponse,redirect
import json

# Create your views here.
from app01 import models
from django.core import serializers
def ab_se(request):
    user_queryset = models.Userinfo.objects.all()
    # user_list = []
    # for user_obj in user_queryset:
    #     user_list.append({
    #         \'username\':user_obj.username,
    #         \'password\':user_obj.password,
    #         \'gender\':user_obj.get_gender_display(),
    #                       })
    # res = json.dumps(user_list)
    res = serializers.serialize(\'json\',user_queryset)   # 注意此处json为字符串
    # return render(request,\'ab_se.html\',locals())
    return HttpResponse(res)

注意:在 http://www.bejson.com/ 中可以在线JSON格式化校验

其结果为

 1 [{
 2     "model": "app01.userinfo",
 3     "pk": 1,
 4     "fields": {
 5         "username": "jason",
 6         "password": "123",
 7         "gender": 1
 8     }
 9 }, {
10     "model": "app01.userinfo",
11     "pk": 2,
12     "fields": {
13         "username": "tank",
14         "password": "234",
15         "gender": 2
16     }
17 }, {
18     "model": "app01.userinfo",
19     "pk": 3,
20     "fields": {
21         "username": "egon",
22         "password": "456",
23         "gender": 3
24     }
25 }, {
26     "model": "app01.userinfo",
27     "pk": 4,
28     "fields": {
29         "username": "sean",
30         "password": "678",
31         "gender": 4
32     }
33 }]
View Code

 

 批量插入

def ab_bc(request):
    # 先插入1000条数据
    # for i in range(1,1001):
    #     models.Book.objects.create(title=\'第%s本书\'%i)
    book_list =[]
    for i in range(1,10001):
        book_list.append(models.Book(title=\'新的%s书\'%i))
    models.Book.objects.bulk_create(book_list)  # 批量插入数据的方式

    book_queryset = models.Book.objects.all()
    return render(request,\'ab_bc.html\',locals())

 

自定义分页器

分页器组件

class Pagination(object):
    def __init__(self,current_page,all_count,per_page_num=10,pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        
        用法:
        queryset = model.objects.all()
        page_obj = Pagination(current_page,all_count)
        page_data = queryset[page_obj.start:page_obj.end]
        获取数据用page_data而不再使用原始的queryset
        获取前端分页样式用page_obj.page_html
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page <1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num


        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # 添加前面的nav和ul标签
        page_html_list.append(\'\'\'
                    <nav aria-label=\'Page navigation>\'
                    <ul class=\'pagination\'>
                \'\'\')
        first_page = \'<li><a href="?page=%s">首页</a></li>\' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = \'<li class="disabled"><a href="#">上一页</a></li>\'
        else:
            prev_page = \'<li><a href="?page=%s">上一页</a></li>\' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = \'<li class="active"><a href="?page=%s">%s</a></li>\' % (i, i,)
            else:
                temp = \'<li><a href="?page=%s">%s</a></li>\' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = \'<li class="disabled"><a href="#">下一页</a></li>\'
        else:
            next_page = \'<li><a href="?page=%s">下一页</a></li>\' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = \'<li><a href="?page=%s">尾页</a></li>\' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append(\'\'\'
                                           </nav>
                                           </ul>
                                       \'\'\')
        return \'\'.join(page_html_list)

后端代码

current_page = request.GET.get(\'page\', 1)    # 当前页数
all_count = book_queryset.count()     # 数据总条数
# 1 现生成一个自定义分页器类对象
page_obj = Pagination(current_page=current_page,all_count=all_count,pager_count=9)
# 2 针对真实的queryset数据进行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end]
return render(request,\'ab_bc.html\',locals())

前端代码

{% for book_obj in page_queryset %}
    <p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}

 

ajax结合sweetalert实现删除二次确认

弹窗组件参考:https://lipis.github.io/bootstrap-sweetalert/ 

代码:

views.py


from app01 import models
from django.http import JsonResponse
import time
def show_user(request):
    \'\'\'
    前后端如果是通过ajax进行交互  那么交互的媒介一般情况下都是一个字典
    :param request:
    :return:
    \'\'\'
    if request.method == \'POST\':
        time.sleep(3)   # 模拟延迟3秒处理再删除
        back_dic = {\'code\':1000,\'msg\':\'\'}
        delete_id = request.POST.get(

以上是关于Django框架进阶6 多对多三种创建方式, Ajax, Content-Type前后端传输数据编码格式, Ajax发送文件数据, django内置的序列化功能, Ajax结合sweetalert实的主要内容,如果未能解决你的问题,请参考以下文章

Python Django 多对多三种创建方式 form组件 cookie和session

2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC多对多表三种创建方式前后端传输数据编码格式contentTypeajax自定义分页器)

多对多三种创建方式forms组件cookies与session

Django 09

多对多三种创建方式,forms组件,cookie和session

Django---进阶7