Django-choices correspondence relationship field value (sex) and MVC science -Ajax hair-MTV json format file format data format -Ajax -contentType achieved with sweetalert deletion confirmation pop - custom finisher - Batch inserted -07

models supplement field

Parameter choices / field (with the lot)

Gender, user education, work status, marital status (within a limited range can be set out, and are available)

app01/models.py

from django.db import models


# Create your models here.
class User(models.Model):
    username = models.CharField(max_length=32)
    age = models.IntegerField()
    choices = (
        (1, '男'), (2, '女'), (3, '其他')
    )
    gender = models.IntegerField(choices=choices)

    """
    1 存choice里面罗列的数字与中文对应关系
         print(user_obj.get_gender_display())
            只要是choices字段 在获取数字对应的注释 固定语法
            get_choices字段名_display()

    2 存没有罗列迟来的数字
        不会报错 还是展示数字
    """


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

Synchronized to the database, and add a few test data

Test test file

As long as the choice field, corresponding to the acquired digital notes, fixed syntax:

get_choices字段名_display(), Kept no list of numbers, does not complain or display digital

Value Features

  • We have come up with correspondence between the corresponding relationship

  • If there is no corresponding relationship, it directly to the original value out

Common cases in CRM

MVC model and MTV science

django claiming MTV frame (in fact, is the essence of MVC)

  • M:models

  • T:templates

  • V: views

MVC

  • M:models
  • V: views
  • C: controller controller (URLs)

Ajax

AJAX (Asynchronous Javascript And XML asynchronous Javascript and XML)

Features: asynchronous submission, partial refresh

For example: instant check when a registered user, the user name exists in the github

Send GET, POST request of several common ways

a 标签的 href 属性                   GET请求
直接在浏览器窗口输入 url 敲回车       GET请求
form 表单提交                       GET/POST
ajax 提交                           GET/POST

The following request is transmitted primarily through ajax

ajax this technology is in Javascript, but Javascript native operation more complicated, we are here for convenience, directly to use jQuery's ajax

The biggest advantage Ajax: without reloading the entire page, you can exchange data with the server and update parts of the page content. (This feature is the feeling to the user request and the completion of the corresponding process unknowingly)

Make a small case with Ajax

There are three input boxes, input boxes first two digital input, click on the send button ajax request page, without refreshing the page, and automatically fills in the number of two in the third box

Here we are jQuery's ajax, do not forget to include jQuery

Ready to work

  • Create a new project, to complete the basic configuration
    • Because use to post the request, so the settings temporarily in the middleware commented csrf
  • The first to write a url address to match the user's browser input
  • And then view function to achieve page to the browser, rendered into a page, a page is returned to the user input box contents.

day57/settings.py

"""
Django settings for day57 project.

Generated by 'django-admin startproject' using Django 1.11.11.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'p0d7eiqh64wgd#!!rso@!wv#4w(%-)6%hb6q^4ci=+h54h@syx'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',  # 1.检查 APP 是否已注册
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',  # 2.检查 csrf中间件 是否已注释掉
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'day57.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,  # 3.检查 templates 文件夹是否已注册
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'day57.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',  # 4.检查 数据库配置信息(本文打算采用 django 自带的 sqlite3 进行测试,就不额外配置数据库了(__init__.py 文件里也就不配了))
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

LOGGING = {  # 5.添加数据库操作语句打印(一有数据库操作就会在 pycharm 控制台打印对应的 SQL 语句)
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [  # 6.配置静态资源路径(方便使用静态资源路径动态解析)
    os.path.join(BASE_DIR, 'static')
]

The bootstrap into the project root directory create a static folder

Configuring url, paper, route distribution (Well a lot of practice)

day57/urls.py

"""day57 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include  # 下面用到了 include ,要自己导入这个模块
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^user/', include('app01.urls')),  # 写成字符串就会根据配置信息自动去查找,就不需要自己导模块过来了
]

app01/urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^index/', views.index, name='user_index'),  # 匹配路由并取别名,方便后期反向解析 url
]

app01/views.py

from django.shortcuts import render


# Create your views here.
def index(request):
    return render(request, 'index.html')  # 用户访问 http://127.0.0.1:8000/user/index/ 直接给他返回 index.html 这个页面

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试页</title>
{#    为了测试方便,这里就用网上的 jquery 了,用 CDN 的形式引入#}
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{#    下面练习一下静态资源路径动态解析,并且 boostrap 放在本地会有语法提示,可以加快开发效率#}
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
{#随便搭一个页面#}
    <div class="container">
        <div class="row">
            <div class="text-center">
                <input type="text"> +
                <input type="text"> =
                <input type="text">
                <button class="btn btn-primary">计算</button>
            </div>
        </div>
    </div>
</body>
</html>

Test whether a browser to access the basic work ready (successfully)

Hands achieve results with Ajax

Ideas analysis

We are entering information, then click on the calculate button and send a request to the backend of ajax, backend to get the request and return the data to the front end, the front end of the data to fill in the results box

As can be seen, our breakthrough is to calculate button click event

app01/urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^index/', views.index, name='user_index'),
    url(r'^compute/', views.compute, name='user_compute'),  # 用来处理用户的计算请求
]

app01/views.py

from django.shortcuts import render, HttpResponse


# Create your views here.
def index(request):
    return render(request, 'index.html')  # 用户访问 http://127.0.0.1:8000/user/index/ 直接给他返回 index.html 这个页面


from django.http import JsonResponse  # 下面发json数据要用到


def compute(request):
    # 判读是否是 ajax 请求
    if request.is_ajax():
        # 定义一个空的字典,用来存放一会儿的返回信息
        back_dic = {

        }
        # 前端 ajax采用的是 post 请求,所以这里这样获取数据
        num1 = request.POST.get('num1')
        num2 = request.POST.get('num2')
        # 判断数据格式是否正确
        if num1.isdigit() and num2.isdigit():
            try:
                res = int(num1) + int(num2)
                back_dic['status'] = 200
                back_dic['res'] = res
            except Exception as e:
                print(e)
                back_dic['status'] = 100
                back_dic['err'] = e
        # 格式不正确返回错误信息
        else:
            back_dic['status'] = 100
            back_dic['err'] = '请输入合法数字!'
        # 用 JsonResponse 将字典打包成 json 格式数据返回给前端
        #   json 格式的数据前端可以直接解析成 前端的自定义对象
        return JsonResponse(back_dic)

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试页</title>
    {#    为了测试方便,这里就用网上的 jquery 了,用 CDN 的形式引入#}
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    {#    下面练习一下静态资源路径动态解析,并且 boostrap 放在本地会有语法提示,可以加快开发效率#}
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
{#随便搭一个页面#}
<div class="container">
    <div class="row">
        <div class="text-center">
            <input type="text" id="num1"> +
            <input type="text" id="num2"> =
            <input type="text" id="res">
            <button class="btn btn-primary" id="button1">计算</button>
        </div>
    </div>
</div>
<script>
    {#    1.为了能够获取到对应输入框和按钮以及输入框的值,我们需要先给他们加上 id #}
    $('#button1').click(function (e) {  {# 2.给我们的 计算 按钮绑定点击事件,点击时用 ajax 发送请求,然后后端计算并返回数值,放在 id 为 res 的 input 里 #}
        $.ajax({  {# 3.Jquery 的 ajax,需要下面几个参数,记得写上(Ajax 的括号内是一个大括号,然后再写的参数) #}
            url: '{% url "user_compute" %}', {# 4.写 ajax 发送请求的地址,这里用的 url 反向解析 #}
            type: 'post', {# 5.采用 post 请求发送数据 #}
            data: {  {# 6.把要发送过去的数据打包 #}
                'num1': $('#num1').val(),  {# 7.获取到 id 为 num1 的标签的 value值 #}
                'num2': $('#num2').val()
            },
            success: function (data) {  {# 8.请求成功的回调函数 #}
                if (data.status == 200) {  {# 9.后端手动设置的码, 200 表示数据类型没问题 #}
                    $('#res').val(data.res);  {# 数据没问题就打印出来 #}
                } else {  {# 10.码不是 200 表示数据类型有误等,弹窗提示错误信息 #}
                    alert(data.err);
                }
            }
        })
    })
</script>
</body>
</html>

Request page View results

request.is_ajax() Way to determine whether the current request is an ajax request (either get or post, as long as the ajax submit, can be identified)

ajax request submitted by post, no name tag attribute it does not matter, we've already specified key value pairs (the main role name in the form of the form)

contentType front end of the transmission data coding format

Encoding format front and rear ends of the transmission data (common)

  1. application/x-www-form-urlencoded
    • form form default encoding format
      • Data format: name = jason & pwd = 123
    • django backend will automatically parse urlencoded encoding format for data and put request.POST for users to get (file transfer when he got the file name)
  2. multipart/form-data
    • django backend will automatically parse the data for as long as is consistent with urlencoded encoding format and put request.POST, as long as you specify the encoding is formdata will automatically parse and put in request.FILES for users to get
  3. json

Summary: The front and rear end of the transmission of data, be sure to ensure that your data formats and encoding format is the same, not recklessly, otherwise it will not take data

ajax submit data

ajax default data submission is urlencoded

Do not conform to the format on the front and rear end coding and data formats agreement on this issue does not occur

Data formats sent ajax json

django backend json format for the data, and does not automatically parse into request.POST or request.FILES inside, it does not parse json format data, but it was intact on the request.body

$('#b1').on('click',function () {
    // 点击按钮 朝后端发送post请求
    $.ajax({
        url: '',  // 控制发送给谁 不写就是朝当前地址提交
        type: 'post',  // 发送方式是post请求
        data: JSON.stringify({'username': 'jason', 'password': 123}),  // 发送的数据
        contentType: 'application/json',  // 告诉后端你这次的数据是json格式

        success: function (data) {  // data形参用来接收异步提交的结果
            // 将后端计算好的结果 通过DOM操作 渲染到第三个input矿中
            $('#i3').val(data)
        }
    })
})

Backend need to manually request.body in json format data acquisition, processing their own

from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def index(request):
    # 验证前后端传输数据的编码格式
    if request.method == 'POST':
        print(request.body)
        # 后端 需要手动去request.body中获取json格式数据  自己处理
        json_str = request.body
        import json
        s = json_str.decode('utf-8')
        ral_d = json.loads(s)
        print(ral_d, type(ral_d))
        return HttpResponse('OK')
    return render(request, 'index.html')

ajax transfer files

How to obtain the file object file tags stored?

  1. First find use jQuery to input tag stored files
  2. The jQuery object into a target native js
  3. Js using native object's method .files [0] obtained file object is stored inside the label
  4. Be sure to specify the two parameters (processData, contentType) are false
 // ajax传输文件
$('#b1').on('click',function () {
    // ajax 传输文件 建议使用内置对象 formdata
    var formData = new FormData();  // 既可以传普通的键值对 也可以传文件
    // 添加普通键值(后续可以改成 for 循环填充)
    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)
        }

    })
})

Serialization assembly

Before and after the end of the separation of knowledge

Separate analog front end, a front end to a transmission format of a large dictionary json

from django.core import serializers  # django自带的一个小型的序列化工具
from app01 import models
import json


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)  # 指定序列化格式为 json
    return render(request, 'index.html', locals())

Json format data received from the preceding paragraph

[{
    "model": "app01.user",
    "pk": 1,
    "fields": {
        "username": "jason",
        "age": 18,
        "gender": 1
    }
}, {
    "model": "app01.user",
    "pk": 2,
    "fields": {
        "username": "tank",
        "age": 24,
        "gender": 3
    }
}, {
    "model": "app01.user",
    "pk": 3,
    "fields": {
        "username": "egon",
        "age": 73,
        "gender": 2
    }
}, {
    "model": "app01.user",
    "pk": 7,
    "fields": {
        "username": "kevin",
        "age": 29,
        "gender": 4
    }
}]

If the format was chaotic all in a row, you can find a tool to help resolve what website ( online check json format )

Currently small serialization module serializers

There are better, rest_framework. . . Later would involve

from app01 import models
from django.core import serializers  # django 自带的一个小型的序列化工具

def reg(request):
    user_list = models.User.objects.all()
    res = serializers.serialize('json', user_list)
    return render(request, 'index.html', locals())

Sweetalert use to build the page (pop)

  • Make sure to configure static resource files settings.py
  • Under the sweetalert over, put under static
  • Incorporated dynamic resolution corresponding to the page: jq, bootstrap (css / js), sweetalert (css / js) (we use depends on the bootstrap)

Buttons below have not written, but also bind id, etc.

Pop Chinese support is not very good, manually modify the style

Adjust the style, Google browser to see the hierarchy, and then overwrite handwriting style (this will not affect other places)

<style>
    div.sweet-alert h2{
        padding-top: 10px;
    }
</style>

sweetalert official website to find a style to come, on the script, the binding event to a button, it triggers

cancelButtonText modify cancel text (added their own)

Button to add custom properties, binding user_id, pop confirm the deletion write ajax where to get past user_id hair ajax

<!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>

The rear end of the transmission jsonResponse dictionary, and the front end can get resolved to automatically custom object, its attributes can be directly operate with dot syntax

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())

Page data is not refreshed problem

Refresh is the most direct way to lazy

This method is not very good (the second paragraph of pop animation is done and it has not refresh the page)

Delete the entire line

Get Parent tag (full line), and then remove it off from the DOM tree by the DOM operation $btnEle.parent().parent().remove()

No. no continuous first matter, the focus is not here (-> 1,3,4,5)

Custom pager

Bulk Insert test data bulk_create

An insertion and an effect, not a little faster (an insertion section 1000, to more than a minute, second plug batch)

l = []

for i in range(10000):
    l.append(models.Book(title=f'书籍{i}'))
models.Book.objects.bulk_create()  # 批量插入数据

Paging

There are several key parameters: how many per page, start page, start bar number, the number of end

Derive their relations law

"""
per_page_num = 10

current_page                start_page                  end_page
    1                           0                           10
    2                           10                          20
    3                           20                          30  
    4                           30                          40

per_page_num = 5

current_page                start_page                  end_page
    1                           0                           5
    2                           5                           10
    3                           10                          15  
    4                           15                          20

start_page = (current_page - 1) * per_page_num
end_page =  current_page* per_page_num


10000
10

1000


10001
10

1001

"""

Can use built-in functions divmod (101, 10) - 10 1 calculates the number of pages>

In the rear circulating rendering html tag (do not distal)

Page edge determination

Using the final version of the realization pager

General third party generic file will create a new utils folder, then inside the python code into

rear end

Creating folders and files, the paged code into them, to import over, use

app01 / utils / mypage.py written paging class, directly used enough

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)

In app01 / views.py use

# ...其他代码
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())
# ...其他代码

templates / booklist.html page

<!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 }}  {# 支持转义,让 html 格式的字符串可以渲染出来 #}
        </div>
    </div>
</div>
</body>
</html>

Guess you like

Origin www.cnblogs.com/suwanbin/p/11576017.html