(day56)八、删除框、批量创建、分页器组件

一、ajax结合sweetalert实现删除按钮的动态效果

  1. 下载sweetalert插件,导入dist文件夹中css和js文件
  2. 挑选弹出框样式,https://lipis.github.io/bootstrap-sweetalert/
  3. 通过自定义标签属性传输数据
  4. 通过标签的查找删除标签,达到删除的作用
<!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 'dist/sweetalert.min.js' %}></script>
    <script src={% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}></script>
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <table class="table-striped table table-bordered table-hover">
                <thead>
                <tr>
                    <th>序号</th>
                    <th>姓名</th>
                    <th>年龄</th>
                    <th>性别</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                {% for user in user_queryset %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ user.username }}</td>
                        <td>{{ user.age }}</td>
                        <td>{{ user.get_gender_display }}</td>
                        <td>
                            <a href="" class="btn btn-success btn-sm">编辑</a>
                            <!--通过自定义标签属性传输user_id-->
                            <a href="#" class="cancel btn btn-danger btn-sm" userId= {{ user.pk }}>删除</a>
                        </td>
                    </tr>
                {% endfor %}

                </tbody>
            </table>
        </div>
    </div>
</div>

<script>
    $('.cancel').click(function () {
        var $btn = $(this);
        console.log($(this))

        swal({
                title: "Are you sure?",
                text: "You will not be able to recover this imaginary file!",
                type: "warning",
                showCancelButton: true,
                confirmButtonColor: "#DD6B55",
                confirmButtonText: "Yes, delete it!",
                cancelButtonText: "No, cancel plx!",
                closeOnConfirm: false,
                closeOnCancel: false
            },

            function (isConfirm) {
                if (isConfirm) {
                    console.log($(this))

                    $.ajax({

                        url: '',
                        type: 'post',
                        // 通过标签自定义属性传输数据
                        data: {'user_id': $btn.attr('userId')},
                        success: function (data) {
                            if (data.code === 1000) {
                                swal("Deleted!", data.msg, "success");
                                // 通过标签的查找删除标签
                                $(this).parent().parent().remove()

                            } else {
                                swal("Cancelled", "Your imaginary file is safe :)", "warning");

                            }
                        }
                    })
                } else {
                    swal("Cancelled", "Your imaginary file is safe :)", "error");
                }
            });
    })
</script>

</body>
</html>
# views.py
from django.shortcuts import render
from django.http import JsonResponse
from app01 import models
# Create your views here.
def home(request):
    if request.is_ajax():
        user_id = request.POST.get('user_id')
        models.User.objects.filter(pk=user_id).delete()
        return JsonResponse({'code':1000,'msg':'删除成功'})
    user_queryset = models.User.objects.all()
    return render(request,'home.html',locals())

二、bulk_create批量插入数据

  1. bulk_create用于批量插入数据,解决大量插入数据耗时长的问题
  2. 先用列表生成数据,再通过bulk_create批量插入数据
def index(request):
    book_list = []
    for i in range(10000):
        book_list.append(models.Book(title=f'第{i}本书'))
    # 批量插入数据
  models.Book.objects.bulk_create(book_list)
    book_queryset = models.Book.objects.all()
    return  render(request,'index.html',locals())

三、自定义分页器

(一)手动推导

def index(request):
    book_queryset = models.Book.objects.all()
    all_page_count = book_queryset.count()  # 数据总个数
    per_page_count = 10  # 每页要展示的数据数目
    page_num,mod = divmod(all_page_count,per_page_count)
    if mod:
        page_num +=1  # 总页数

    current_page = request.GET.get('page',1)  # 默认第一页
    current_page = int(current_page)

    xxx = current_page
    # 前六页和后六页
    if current_page < 6:
        xxx = 6
    elif current_page < page_num and current_page > page_num-6:
        xxx = page_num-6

    html = ''
    for i in range(xxx-5,xxx+6):
        if i==current_page:
            html += f'<li class="active"><a href="?page={i}">{i} <span class="sr-only">(current)</span></a></li>'
        else:
            html+= f'<li class=""><a href="?page={i}">{i} <span class="sr-only">(current)</span></a></li>'

    start_page = (current_page-1) * per_page_count 
    end_page = current_page*per_page_count
    book_queryset = book_queryset[start_page:end_page]

    return render(request,'index.html',locals())
<!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 'dist/sweetalert.min.js' %}></script>
    <script src={% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}></script>
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-8">
            {% for book_obj in book_queryset %}
                <p>{{ book_obj }}</p>
            {% endfor %}

            <nav aria-label="Page navigation">
                <ul class="pagination">
                    <li>
                        <a href="#" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                    {{ html|safe }}
                    <li>
                        <a href="#" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                </ul>
            </nav>
        </div>
    </div>
</div>
</body>
</html>

(二)自定义分页器

(1)模板

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)

(2)用法

  1. 应用中创建utils文件夹
  2. 文件夹中创建mypage.py文件
  3. 视图函数中导入该文件
  4. 当前页:current_page
  5. 数据总个数:all_count
  6. 实例化对象:page_obj
  7. 切片
# views.py
from app01.utils.mypage import Pagination
def index(request):
    current_page = request.GET.get('page',1)
    all_count = book_queryset.count()
    page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10,pager_count=5)
    page_queryset = book_queryset[page_obj.start:page_obj.end] 
    return render(request,'index.html',locals())
<!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-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            {% for book in page_queryset %}  
                <p>{{ book }}</p>
            {% endfor %}
            {{ page_obj.page_html|safe }}
        </div>
    </div>
</div>


</body>
</html>
  1. orm查询优化

    1. only和defer

      1. only
        1. only返回的是queryset对象,本质就是列表套数据对象
        2. 该对象内只含有only括号内指定的属性,但是其他属性也可以获取,会自动从数据库重新获取
      2. defer
        1. defer返回的是queryset对象,本质就是列表套数据对象
        2. 该对象内只含有除了defer括号内所指定的其他属性,指定属性也可获取,也会自动从数据库重新获取
    2. select_related和prefetch_related

      1. select_related
        1. 括号内只能放外键字段,并且外键字段的类型只能是一对多或者多对多
        2. 内部是联表操作,返回的是一个queryset列表套数据对象
        3. 获取外键表数据时,不会再访问数据库
      2. prefetch_related
        1. 内部是子查询,括号内外键字段无限制
        2. 内部是联表操作,返回的是一个queryset列表套数据对象
        3. 获取外键表数据时,不会再访问数据库

      第一个方法联表操作比较耗时、第二个方法访问数据库比较耗时

  2. choices参数

    1. 提前定义好对应关系
    2. 再通过字段的choices参数指定关系
    3. get_字段名_display:获取对应关系
  3. MTC和MVC模型

    1. MTC

      1. Models
      2. Templates
      3. Views
    2. MVC

      1. Models
      2. Views
      3. Controller

      django自称是MTV,本质上还是MVC

  4. AJAX

    1. 异步提交
    2. 局部刷新
  5. AJAX基本语法结构

    1. url:后端的地址,特性和action一样
  6. type:请求方式
    1. data:传输数据
  7. success:基于ajax,后端返回的结果(HttpResponse)会被回调函数捕获,不会影响整个页面

          // 基于Jquery封装好的ajax,确保jQuery导入
          $.ajax({
              url:'',
              type:'post',
              data:{'username':'wick'}
              success:function(data){
    
          }
          })
  8. 前后端数据传输编码格式
    1. urlencoded
      1. 数据格式:usernamewick&password=123
      2. django针对符合urlencoded编码格式的数据,会自动解析并封装到request.POST中
    2. formdata
      1. form表单发送文件必须要指定的编码格式
      2. 可以发文件也可以发普通键值对
      3. django后端会自动识别,将内部符合urlencoded编码格式的数据,会自动东借西并封装到request.FILES中
    3. application/json
      1. 用来发送json格式数据
      2. 目前只有ajax能发送jaon格式数据
  9. ajax发送json格式数据
    1. contenType:'application/json'
    2. JSON.stringify({'username':'wick'$'password':123})
    3. django针对json格式数据不会自动处理,会封装在requerst.body内,需要手动反序列化
  10. ajax发送文件数据
    1. 先生成一个内置对象:var MyFormData=new FormData()
    2. 通过append向对象内添加数据(可以是普通键值对,也可以是文件)
      1. 普通键值对:MyFormData.append('name','wick')
      2. 文件数据:MyFormData.append('file',$('input')[0].file[0])
    3. 额外指定两个参数
      1. contentType:false
      2. processData:false

猜你喜欢

转载自www.cnblogs.com/wick2019/p/11972671.html