• Django与AJAX-choice字段-MTV和MVC模型-sweetalert搭建页面


    Django中的choice字段

      应用的场景:

        用户信息举列:如用户性别、婚否、学历、工作状态等可以列举出来供选择的信息

    书写models创建表模型:

    数据的获取和查询:

     总结:

    """
          1 存choice里面罗列的数字与中文对应关系
               print(user_obj.get_gender_display())
                  只要是choices字段 在获取数字对应的数据 固定语法
                  get_choices字段名_display()
    
          2 存没有罗列出来的数字
              不会报错 还是展示数字
          """

    MTV和MVC框架 (了解概念)

    MVC(Model View Controller 模型-视图-控制器)

    MTV(Model Templates View 模型-模板-视图):

    区别:

    MVC中的View的目的是「呈现哪一个数据」,而MTV的View的目的是「数据如何呈现」。

       MTV:是Django框架,自己自称的

        M:models模型

        T:templates模板

        V:views视图

       MVC:目前大部分web框架的本质

        M:models

        V:views

        C:controller  控制器(urls)

    本质:MTV其实也是MVC

    Django与AJAX

      关键理解:异步提交,局部刷新

    例如github官网的注册界面:

      注册用户名时,时刻监测用户名是否存在,向后端发送请求,进行动态的校验.

    目前所接触到的向后端发送请求方式:

      GET/POST请求

    """
    前端中的<a> </a>标签 >>>>>GET请求       
    浏览器中输入的url搜索>>>>>GET请求  
    from表单  >>>>>>>>>>>>>>>GET/POST请求
    AJAX》>>>>>>>>>>>>>>>>>GET/POST请求
    
    """

    AJAX简介

      AJAXAsynchronous Javascript And XML)翻译成中文就是异步的JavascriptXML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

    AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

    AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

    AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

    • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
    • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

    AJAX:有点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。

    例子:

      页面上有三个input框,在前两个input框中输入数字,点击按钮 发送ajax请求,不刷新页面的情况下,第三个框中自动算出两数之和。

    前端向后端发送请求需注意:改成让Django知道走POST请求

     views.py

    from django.shortcuts import render,reverse,HttpResponse,redirect
    
    # Create your views here.
    
    def index(request):
        print(request.is_ajax())  # 用来判断当前请求方式是否是ajax请求
        if request.is_ajax():
            if request.method == 'POST':
                # print(request.POST)
                i1 = request.POST.get('i1')
                i2 = request.POST.get('i2')
    
                # 后端获取的前端数据 都是字符串格式
                res = int(i1) + int(i2)
                return HttpResponse(res)
            return reverse(request,'index.html')

    url,py

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/',views.index),
    ]

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
         <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.slim.js"></script>
    </head>
    <body>
    <input type="text" id="l1">+<input type="text" id="l2">=<input type="text" id="l3">
    <button id="l3">求和</button>
    <script> // 绑定点击事件
        $('#l3').on('click',function () {
                    {#alert(123)#}
                    // 点击按钮 朝后端发送post请求
                    $.ajax({
                        url:'',  // 控制发送给谁 不写就是朝当前地址提交
                        type:'post',  // 发送方式是post请求
                        data:{'i1':$('#l1').val(),'l2':$('#l2').val()},  // 发送的数据
                        success:function (data) {  // data形参用来接收异步提交的结果
                            // 将后端计算好的结果 通过DOM操作 渲染到第三个input框中
                            $('#l3').val(data)
                        }
                    })
                })
    </script>
    </body>
    </html>

    前端书写AJAX部分

    运行的结果是:点击求和后向后端发送POST请求,取到结果并展示

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

    常用的数据编码格式有三类:

    1.urlencoded  >>>>>  数据格式:name=jack&pwd=123&boby=running
    2.formdata    >>>>>>>>>     传文件也支持传普通的键值对:name=jack&pwd=123&boby=running
    3.json     >>>>>>>>       josn格式数据(from表单是无法发送Json格式的数据的)

      form 表单:默认使用的编码格式是urlencoded,数据格式是:name=jason&pwd=123;发送到后端,

    django后端针对urlencoded编码格式的数据会自动解析并放到request.POST中供用户获取。

    可以修改为formdata 传文件
          django后端针对只要是符合urlencoded编码格式的数据(name=jason&pwd=123)都会自动解析并放到request.POST中供用户获取

    如果是文件 只要你指定的编码是formdata 就会自动解析并放到request.FILES中

    ajax提交数据:提交的方式默认也是urlencoded

    django后端针对不同的编码格式是如何处理的?

    1、只要是符合urlencoded编码格式  都会被后端自动获取并解析放到request.POST中
    2、如果是符合formdata那么文件会自动被解析放到request.FILES中
    3、如果是json格式 后端默认不解析 以二进制的形式就放在request.body你可以自己手动处理即可

    ajax发送json格式数据

    <script>
        $('#b1').on('click',function () {
            alert(123)
            // 点击按钮 朝后端发送post请求
            $.ajax({
                url:'',  // 控制发送给谁 不写就是朝当前地址提交
                type:'post',  // 发送方式是post请求
                data:JSON.stringify({'username':'jason','password':123}),  // 发送的数据
                contentType:'application/json',  // 告诉后端你这次的数据是json格式
    
                success:function (data) {  // data形参用来接收异步提交的结果
                    alert(data)
                    // 将后端计算好的结果 通过DOM操作 渲染到第三个input矿中
                    $('#i3').val(data)
                }
    
            })
        // {)
    </script>

     要指定传输的数据格式统一

    后端验证数据格式:

    def index(request):

    #验证前后端传输数据的编码格式
        if request.method =='POST':
            print('request.POST',request.POST)
            print('request.FILES',request.FILES)
            jason_str = request.body
            import json
            # 后端 需要手动去request.body中获取json格式数据 自己处理
            res = jason_str.decode('utf-8')
            ral_d = json.loads(res)
            print(ral_d)
            return HttpResponse('OK')
        return render(request,'index.html')

    总结:前后端在传输数据的时候,一定要保证数据格式和你的编码保持一致性的.

    通常情况下,后端针对ajax交互,都是采取字典的形式

    基于AJAX传文件:

      关键字formData

    传文件:如何获取文件标签存储的问文件对象?固定的语法

      1、先用jQuery查找到存储文件的input标签

      2、将jQuery对象转成原生Javascript对象

      3、利用原生Javascript对象的方法.files[0]获取到标签内部存储的文件对象

    {#// ajax传输文件#}
        $('#b1').on('click',function () {
            // ajax传输文件 建议使用内置对象formdata
            var formData = new FormData();  // 既可以传普通的键值对 也可以传文件
            // 添加普通键值
            formData.append('username','jason');
            formData.append('password','123');
            //固定的格式
            formData.append('my_file',$('#d1')[0].files[0]);
            $.ajax({
                url:'',  // 控制发送给谁 不写就是朝当前地址提交
                type:'post',  // 发送方式是post请求
                data:formData, // 发送的数据
                // ajax发送文件需要指定两个额外的参数
                
                processData:false,  // 告诉前端不要处理数据
                contentType:false,  // 不适用任何编码,因为formdata对象自身自带编码 django后端也能够识别formdata对象
                success:function (data) {  // data形参用来接收异步提交的结果
                    alert(data)
                    // 将后端计算好的结果 通过DOM操作 渲染到第三个input矿中
                    $('#i3').val(data)
                }
    
            })

    注意固定的格式及一些参数的使用

    序列化组件

      Django内置的serializers

      简单的解释就是前端想拿到由ORM得到数据库中里面得一个个用户对象,为了简便操作,

    后端直接将实例化出来的数据对象直接发送给客户端,这时候就需要用到序列化模块。

    主要是考虑Json序列化字典的数据格式,传输的数据类型比较多,也可以以K:V键值对的形式取值。

    from django.core import serializers  # django自带的一个小型的序列化工具
    def reg(request):
        user_list = models.User.objects.all()
      原来的数据传输:
    # 将所有的数据都组织成一个符合json的一个个的字典 # user_l = [] # for user_obj in user_list: # user_l.append( # json.dumps({'username':user_obj.username, # 'age':user_obj.age, # 'gender':user_obj.get_gender_display() # }) # ) res = serializers.serialize('json',user_list) # return render(request,'index.html',locals())

     利用在这json在线格式转换工具:

     AJAX结合sweetalert插件的应用(动态弹框)

      实现以下的动态弹框提示,点击下载Bootstrap-sweetalert项目。需要导入的插件,统一放入static文件中配置到settings.py文件下.

    views.py

    from django.http import JsonResponse
    import time
    def userlist(request):
        if request.is_ajax():
            time.sleep(3)
            """
            一般情况下 针对ajax请求 后端通常都是返回一个字典
            """
            back_dic = {'code':100,'msg':''}
            # 直接获取用户想删除的数据的id值
            delete_id = request.POST.get('delete_id')
            # 直接利用queryset方法 批量删除
            models.User.objects.filter(pk=delete_id).delete()
            # 要给前端ajax返回一个消息(字典)
            back_dic['msg'] = '真的删除了!'
            return JsonResponse(back_dic)
    
    
        user_list = models.User.objects.all()
        return render(request,'userlist.html',locals())

    userlist.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>
        {% load static %}
        <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
        <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}">
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
        <script src="{% static 'dist/sweetalert.min.js' %}"></script>
    
        <style>
            div.sweet-alert h2{
                padding-top: 10px;
            }
        </style>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <h2 class="text-center">数据展示</h2>
                <table class="table-striped table table-hover table-bordered">
                    <thead>
                        <tr>
                            <th>序号</th>
                            <th>主键</th>
                            <th>用户名</th>
                            <th>年龄</th>
                            <th>性别</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for user in user_list %}
                            <tr>
                                <td>{{ forloop.counter }}</td>
                                <td>{{ user.pk }}</td>
                                <td>{{ user.username }}</td>
                                <td>{{ user.age }}</td>
                                <td>{{ user.get_gender_display }}</td>
                                <td>
                                    <button class="btn btn-primary btn-sm">编辑</button>
                                    <button class="btn btn-danger btn-sm del" user_id="{{ user.pk }}">删除</button>
                                </td>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <script>
        $('.del').click(function () {
            // 获取当前标签对象
            var $btnEle = $(this);
    
            swal({
              title: "你确定要删吗?",
              text: "你要是删了,你就准备跑路吧!",
              type: "warning",
              showCancelButton: true,
              confirmButtonClass: "btn-danger",
              confirmButtonText: "是的,老子就要删!",
              cancelButtonText: "算了,算了!",
              closeOnConfirm: false,
              showLoaderOnConfirm: true
            },
            function(){
                // 朝后端发送ajax请求
                $.ajax({
                    url:'',
                    type:'post',
                    data:{'delete_id':$btnEle.attr('user_id')},
                    success:function (data) {  // 后端发字典过来 前端不需要你手动转 会自动帮你转换成js自定义对象
                        if (data.code == 100){
                            {#window.location.href = '';  // 不写就是条到当前页面#}
                            // 通过DOM操作 实时改变页面
                            // 将被点击的删除按钮所在的那一行直接从DOM树中删掉
                            $btnEle.parent().parent().remove();
                            swal("删掉了!", "赶紧回去收拾行李吧,准备跑路!", "success");
                        }else{
                            swal('发生了未知的错误','估计是有bug了','info')
                        }
                    }
                });
    
            });
        })
    </script>
    
    </body>
    </html>

    效果如下:

    自定义分页器

    直接拷贝代码然后导入使用即可:

    class Pagination(object):
        def __init__(self, current_page, all_count, per_page_num=2, 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)

    导入使用

    from app01.utils.mypage import Pagination
    def book(request):
        # 使用封装好的自定义分页器
        book_list = models.Book.objects.all()
        current_page = request.GET.get("page",1)
        all_count = book_list.count()
        page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
        page_queryset = book_list[page_obj.start:page_obj.end]
    
        return render(request,'booklist.html',locals())

    booklist.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>
        {% load static %}
        <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
        <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}">
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
        <script src="{% static 'dist/sweetalert.min.js' %}"></script>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                {% for book in page_queryset %}
                <p>{{ book.title }}</p>
                {% endfor %}
                {{ page_obj.page_html|safe }}
            </div>
        </div>
    </div>
    </body>
    </html>

      

      

  • 相关阅读:
    20172305 2017-2018-2 《程序设计与数据结构》第十一周学习总结
    20172305 2017-2018-2 《程序设计与数据结构》实验四报告
    20172305 2017-2018-2 《程序设计与数据结构》实验三报告
    20172305 《程序设计与数据结构》第十周学习总结
    20172305 《程序设计与数据结构》第九周学习总结
    20172305 结对编程项目-四则运算 第二周 阶段总结
    20172305 《程序设计与数据结构》第八周学习总结
    20172305 结对编程项目-四则运算 第一周 阶段总结
    20172305 2017-2018-2 《程序设计与数据结构》实验二报告
    20172305 《程序设计与数据结构》第七周学习总结
  • 原文地址:https://www.cnblogs.com/Gaimo/p/11575462.html
Copyright © 2020-2023  润新知