day67-django-前后端编码格式、Ajax、django序列化组件、批量插入、分页器

每日测验

"""
今日考题:
1.choices参数的应用场景有哪些,如何获取该字段的值
2.django是什么模型的框架,简述MTV与MVC模型
3.多对多表关系有几种创建方式,各有什么特点?
4.什么是ajax,请手写出ajax的基本语法结构及重要参数含义
"""

昨日内容回顾

在django部分,如果你写代码的时候报错了

"""
1.pycharm窗口提示,前端console界面
2.仔细核对代码(单词写错写多)
3.浏览器缓存没有清除
4.端口号可能冲突了,一直跑的是之前的项目
5.重启你的计算机
(自己学会百度搜索问题,出现bug千万不要慌 要冷静分析 自己想出一个排查思路)
"""
  • 图书管理系统图书的增删改查

    """
    将你之前所学的知识点尽量全部都用上(每个人都应该自己能够独立的完成)
    """
    
  • choices参数

    """
    在设计表的时候 针对可以列举完全的可能性字段
    一般都是用choices参数
    """
    gender_choices = ((1,'male'),(2,'female'),(3,'others'))
    gender = models.IntegerField()
    
    # 针对具有choices参数的字段 存储数据的时候还是按照字段本身的数据类型存储没有其他的约束,但是如果你存的字段在你列举的范围内 那么可以自动获取对应关系
    user_obj.gender  # 数字
    user_obj.get_gender_display()  # 固定格式 get_choices参数字段名_display()
    """有对应关系就拿对应关系,没有则还是数据本身不会报错"""
    
    # 自己看看一些模型表的设计 体会choices参数的使用
    
  • MTV与MVC模型

    """
    django自称是MTV框架,但是它的本质其实还是MVC
    """
    
  • 多对多三种创建方式

    # 全自动(本地测试用这个比较方便)
    	authors = models.ManyToManyField(to="Author")
    	# 自动创建第三张关系表 扩展性差  add,remove,clear,set
      
    # 纯手动(基本不用)
    	# 自己创建第三张表 自己建外键
      # 扩展性高 但是无法利用orm简便的查询方法了
    
    # 半自动(实际项目用这个,扩展性好)
    class Book(models.Model):
    	authors = models.ManyToManyField(to="Author",
                                       through='Book2Author',
                                       through_fields=('book','author')
                                      )
    class Author(models.Model):
    	books = models.ManyToManyField(to="Author",
                                       through='Book2Author',
                                       through_fields=('author','book')
                                      )
    class Book2Author(models.Model):
      book = 外键()
      author = 外键()
      """
      第三张关系表 还是需要你自己手动建
      但是你可以告诉django orm可以使用orm简便查询方法
      """
    
  • ajax

    """
    异步提交
    局部刷新
    
    参考案例:github注册实时获取用户名发送给后端确认并动态展示校验结果(页面不刷新)
    复习:input框实时监测事件	input事件
    
    我们学的是jQuery版本的ajax,所以你必须要确保html页面已经提前加载了jQuery
    """
    # ajax基本语法
    $.ajax({
      url:'',  # 朝后端哪个地址发送 跟action三种书写方式一致
      type:'get/post',  # 提交方式 默认get 跟form表单method参数一致
      data:{'username':'jason','password':123},  # 要发送的数据
      success:function(args){
        # 异步回调处理机制
      } 
    })
    """
    当你在利用ajax进行前后端交互的时候
    后端无论返回什么都只会被回调函数接受 而不再影响这个浏览器页面了
    """
    
    # 扩展 参数  代码发布项目还会涉及
    dataType:'JSON'
    """
    当后端是以HttpResponse返回的json格式的数据
    默认是不会自动反序列化的
    	1.自己手动JSON.parse()
    	2.配置dataType参数
    """
    
    # 结论:写ajax的时候 你可以直接将dataType参数加上 以防万一 或者后端就用JsonResonse
    $.ajax({
      url:'',  # 朝后端哪个地址发送 跟action三种书写方式一致
      type:'get/post',  # 提交方式 默认get 跟form表单method参数一致
      dataType:'JSON',  
      data:{'username':'jason','password':123},  # 要发送的数据
      success:function(args){
        # 异步回调处理机制
      } 
    })
    

今日内容概要

  • 前后端传输数据的编码格式(contentType)
  • ajax发送json格式数据
  • ajax发送文件数据
  • ajax结合sweetalert实现删除按钮的二次确认
  • django自带的序列化组件(drf做铺垫)
  • 批量插入
  • 自己写一个分页器(只需要掌握分页器的推导思路即可)
  • 自定义分页器的使用(简单几行代码即可 需要掌握)
  • forms组件

今日内容详细

前后端传输数据的编码格式(contentType)

参看编码格式是在 request里的contentType中

# 我们主要研究post请求数据的编码格式
"""
get请求数据就是直接放在url后面的
url?username=jason&password=123
"""

# 可以朝后端发送post请求的方式
"""
1.form表单
2.ajax请求
"""

  
"""
前后端传输数据的编码格式
	urlencoded
	
	formdata
	
	json
"""
# 研究form表单
	默认的数据编码格式是urlencoded
	数据格式:username=jason&password=123
	django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中
  	username=jason&password=123	>>> request.POST
  
  如果你把编码格式改成formdata,那么针对普通的键值对还是解析到request.POST中而将文件解析到request.FILES中.wsgi一次封装,django进行的二次封装
  
  form表单是没有办法发送json格式数据的
 

# 研究ajax
	默认的编码格式也是urlencoded
	数据格式:username=jason&age=20
	django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中。所以我们才能通过post.get获取到Ajax提交的数据
  	username=jason&age=20	>>> request.POST

ajax发送json格式数据

"""
宗旨:前后端传输数据的时候一定要确保编码格式跟数据真正的格式是一致的
不要骗人家!!! 例如下面的

{"username":"jason","age":25}  JSON格式
	在request.POST里面肯定找不到
	
	django针对json格式的数据 不会做任何的处理 
	
request对象方法补充
	request.is_ajax()
		判断当前请求是否是ajax请求 返回布尔值

"""

<script>
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:JSON.stringify({'username':'jason','age':25}),
            contentType:'application/json',  // 指定编码格式
            success:function () {

            }
        })
    })
</script>

        json_bytes = request.body
        json_str = json_bytes.decode('utf-8')
        json_dict = json.loads(json_str)

        # json.loads括号内如果传入了一个二进制格式的数据那么内部自动解码再反序列化
        json_dict = json.loads(json_bytes)
        
"""
ajax发送json格式数据需要注意点
	1.contentType参数指定成:application/json
	2.数据是真正的json格式数据
	3.django后端不会帮你处理json格式数据需要你自己去request.body获取并处理
"""

ajax发送文件

下面的代码必须要记住

"""
ajax发送文件需要借助于js内置对象FormData
"""
<script>
    // 点击按钮朝后端发送普通键值对和文件数据
    $('#d4').on('click',function () {
        // 1 需要先利用FormData内置对象
        let formDateObj = new FormData();
        // 2 添加普通的键值对
        formDateObj.append('username',$('#d1').val());
        formDateObj.append('password',$('#d2').val());
        // 3 添加文件对象
        formDateObj.append('myfile',$('#d3')[0].files[0])
        // 4 将对象基于ajax发送给后端
        $.ajax({
            url:'',
            type:'post',
            data:formDateObj,  // 直接将对象放在data后面即可

            // ajax发送文件必须要指定的两个参数
            contentType:false,  // 不需使用任何编码 django后端能够自动识别formdata对象
            processData:false,  // 告诉你的浏览器不要对你的数据进行任何处理

            success:function (args) {
            }
        })


    })
</script>

def ab_file(request):
    if request.is_ajax():
        if request.method == 'POST':
            print(request.POST)
            print(request.FILES)
    return render(request,'ab_file.html')
  
"""
总结:
	1.需要利用内置对象FormData
		// 2 添加普通的键值对
        formDateObj.append('username',$('#d1').val());
        formDateObj.append('password',$('#d2').val());
        // 3 添加文件对象
        formDateObj.append('myfile',$('#d3')[0].files[0])
	2.需要指定两个关键性的参数
		contentType:false,  // 不需使用任何编码 django后端能够自动识别formdata对象
        processData:false,  // 告诉你的浏览器不要对你的数据进行任何处理
	3.django后端能够直接识别到formdata对象并且能够将内部的普通键值自动解析并封装到request.POST中 文件数据自动解析并封装到request.FILES中
"""

django自带的序列化组件(drf做铺垫)

"""
如果发现你可以直接使用MySQL但是无法使用sqlite3
不要慌张不要恐惧 你只需要按照之前MySQL的操作将sqlite3的驱动装一下即可
"""
# 需求:在前端给我获取到后端用户表里面所有的数据 并且要是列表套字典
import json
from django.http import JsonResponse
from django.core import serializers
def ab_ser(request):
    user_queryset = models.User.objects.all()
    # [{},{},{},{},{}]
    # user_list = []
    # for user_obj in user_queryset:
    #     tmp = {
    #         'pk':user_obj.pk,
    #         'username':user_obj.username,
    #         'age':user_obj.age,
    #         'gender':user_obj.get_gender_display()
    #     }
    #     user_list.append(tmp)
    # return JsonResponse(user_list,safe=False)
    # return render(request,'ab_ser.html',locals())

    # 上面的过于繁琐。使用序列化serializers模块
    res = serializers.serialize('json',user_queryset)
    """会自动帮你将数据变成json格式的字符串 并且内部非常的全面"""
    return HttpResponse(res)
"""
[
 {"pk": 1, "username": "jason", "age": 25, "gender": "male"}, 
 {"pk": 2, "username": "egon", "age": 31, "gender": "female"},
 {"pk": 3, "username": "kevin", "age": 32, "gender": "others"}, 
 {"pk": 4, "username": "tank", "age": 40, "gender": 4}
 ]
前后端分离的项目
    作为后端开发的你只需要写代码将数据处理好
    能够序列化返回给前端即可 
        再写一个接口文档 告诉前端每个字段代表的意思即可
        
        
[
{   "model": "app01.user", 
    "pk": 1, 
    "fields": {"username": "jason", "age": 25, "gender": 1}}, 
    
{   "model": "app01.user", 
    "pk": 2, 
    "fields": {"username": "egon", "age": 31, "gender": 2}}, 
    
{   "model": "app01.user", 
    "pk": 3, 
    "fields": {"username": "kevin", "age": 32, "gender": 3}},
     
{   "model": "app01.user", 
    "pk": 4, 
    "fields": {"username": "tank", "age": 40, "gender": 4}}
]
写接口就是利用序列化组件渲染数据然后写一个接口文档 该交代交代一下就完事
"""

ajax结合sweetalert

"""
自己要学会如何拷贝
学会基于别人的基础之上做修改
研究各个参数表示的意思 然后找葫芦画瓢
"""
<script>
    $('.del').on('click',function () {
        // 先将当前标签对象存储起来
        let currentBtn = $(this);
        // 二次确认弹框
        swal({
          title: "你确定要删吗?",
          text: "你可要考虑清除哦,可能需要拎包跑路哦!",
          type: "warning",
          showCancelButton: true,
          confirmButtonClass: "btn-danger",
          confirmButtonText: "是的,老子就要删!",
          cancelButtonText: "算了,算了!",
          closeOnConfirm: false,
          closeOnCancel: false,
          showLoaderOnConfirm: true
        },
        function(isConfirm) {
          if (isConfirm) {
                // 朝后端发送ajax请求删除数据之后 再弹下面的提示框
                $.ajax({
                    {#url:'/delete/user/' + currentBtn.attr('delete_id'),  // 1 传递主键值方式1#}
                    url:'/delete/user/',  // 2 放在请求体里面
                    type:'post',
                    data:{'delete_id':currentBtn.attr('delete_id')},
                    success:function (args) {  // args = {'code':'','msg':''}
                        // 判断响应状态码 然后做不同的处理
                        if(args.code === 1000){
                            swal("删了!", args.msg, "success");
                            // 1.lowb版本 直接刷新当前页面
                            {#window.location.reload()#}
                            // 2.利用DOM操作 动态刷新
                            currentBtn.parent().parent().remove()
                        }else{
                            swal('完了','出现了位置的错误','info')
                        }
                    }

                })

          } else {
            swal("怂逼", "不要说我认识你", "error");
          }
        });
    })

</script>

批量插入

def ab_pl(request):
    # 先给Book插入一万条数据
    # for i in range(10000):
    #     models.Book.objects.create(title='第%s本书'%i)
    # # 再将所有的数据查询并展示到前端页面
    book_queryset = models.Book.objects.all()

    # 批量插入
    # book_list = []
    # for i in range(100000):
    #     book_obj = models.Book(title='第%s本书'%i)
    #     book_list.append(book_obj)
    # models.Book.objects.bulk_create(book_list)
    """
    当你想要批量插入数据的时候 使用orm给你提供的bulk_create能够大大的减少操作时间
    :param request: 
    :return: 
    """
    return render(request,'ab_pl.html',locals())

分页器

"""
总数据100 每页展示10 需要10
总数据101 每页展示10 需要11
总数据99 每页展示10  需要10

如何通过代码动态的计算出到底需要多少页?


在制作页码个数的时候 一般情况下都是奇数个		符合中国人对称美的标准
"""
# 分页
    book_list = models.Book.objects.all()

    # 想访问哪一页
    current_page = request.GET.get('page',1)  # 如果获取不到当前页码 就展示第一页
    # 数据类型转换
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1
    # 每页展示多少条
    per_page_num = 10
    # 起始位置
    start_page = (current_page - 1) * per_page_num
    # 终止位置
    end_page = current_page * per_page_num

    # 计算出到底需要多少页
    all_count = book_list.count()

    page_count, more = divmod(all_count, per_page_num)
    if more:
        page_count += 1

    page_html = ''
    xxx = current_page
    if current_page < 6:
        current_page = 6
    for i in range(current_page-5,current_page+6):
        if xxx == i:
            page_html += '<li class="active"><a href="?page=%s">%s</a></li>'%(i,i)
        else:
            page_html += '<li><a href="?page=%s">%s</a></li>'%(i,i)



    book_queryset =  book_list[start_page:end_page]
    
"""
django中有自带的分页器模块 但是书写起来很麻烦并且功能太简单
所以我们自己想法和设法的写自定义分页器

上述推导代码你无需掌握 只需要知道内部逻辑即可

我们基于上述的思路 已经封装好了我们自己的自定义分页器 
之后需要使用直接拷贝即可
"""

作业

"""
必做
1.整理今日内容到博客
2.熟练掌握ajax发送json数据和文件数据代码
3.自己完成按钮的二次确认操作(ajax+sweetalert)
4.尝试理解自定义分页器逻辑,自己推导出简易版本代码
选做
1.阅读博客,预习自定义分页器封装版本使用方式
"""
原文地址:https://www.cnblogs.com/zdw20191029/p/14553302.html