分页组件与CBV

一. 自定义分页

1.准备工作

(1).首先在models.py中创建一张book表用来存储数据

1 from django.db import models
2 class Book(models.Model):
3     title=models.CharField(max_length=32)
4     price=models.CharField(max_length=32)
5     def __str__(self):
6         return self.title

(2)index.html中创建大量数据

 1 for j in range(100):
 2     result=""
 3     for i in range(6):
 4         up=chr(random.randint(65,90))
 5         low=chr(random.randint(97,122))
 6         num=str(random.randint(0,9))
 7         choice=random.choice([up,low,num])
 8         result=choice+result
 9     Book.objects.create(title=result,price=j*j)
10 return HttpResponse("ok")

2.urls.py中添加一个路径

1 urlpatterns = [
2     path('admin/', admin.site.urls),
3     path('index/', views.index),
4 ]

3.视图函数index的准备工作:在一个新的脚本中编写Pagination类

 1 class Pagination():
 2     def __init__(self, current_page_num, all_count, request, per_page_num=5, pager_count=11):
 3         """
 4         封装分页相关数据
 5         :param current_page_num: 当前访问页的数字
 6         :param all_count:    分页数据中的数据总条数
 7         :param per_page_num: 每页显示的数据条数
 8         :param pager_count:  最多显示的页码个数
 9         """
10         try:
11             current_page_num = int(current_page_num)
12         except Exception as e:
13             current_page_num = 1
14         if current_page_num < 1:
15             current_page_num = 1
16         self.current_page_num = current_page_num
17         self.all_count = all_count
18         self.per_page_num = per_page_num
19         all_pager, tmp = divmod(all_count, per_page_num)
20         if tmp:
21             all_pager += 1
22         self.all_pager = all_pager
23         self.pager_count = pager_count
24         self.page_count_half = int((pager_count - 1) / 2)
25         import copy
26         self.params = copy.deepcopy(request.GET)
27 
28     @property
29     def start(self):
30         return int((self.current_page_num - 1) * self.per_page_num)
31 
32     @property
33 
34     def end(self):
35         return int(self.current_page_num * self.per_page_num)
36 
37     def page_html(self):
38         if self.all_pager<=self.pager_count:
39             page_start=1
40             page_end=self.all_pager+1
41         else:
42             if self.current_page_num<=self.page_count_half:
43                 page_start=1
44                 page_end=self.pager_count+1
45             else:
46                 if self.current_page_num >(self.all_pager-self.page_count_half):
47                     page_start=self.all_pager-self.pager_count+1
48                     page_end=self.all_pager+1
49                 else:
50                     page_start=self.current_page_num-self.page_count_half
51                     page_end=self.current_page_num+self.page_count_half+1
52         page_html_list=[]
53         first_page='<li><a href="?page=%s">首页</li>' % 1
54         page_html_list.append(first_page)
55         if self.current_page_num<=1:
56             prev_page="<li class='disabled'><a href='#'>上一页</a></li>"
57         else:
58             prev_page = "<li ><a href='?page=%s'>上一页</a></li>" % (self.current_page_num-1)
59         page_html_list.append(prev_page)
60         for i in range(page_start,page_end):
61             self.params["page"]=i
62             if i==self.current_page_num:
63                 temp="<li class='active'><a href='?%s'>%s</a></li>" % (self.params.urlencode(),i)
64             else:
65                 temp = "<li><a href='?%s'>%s</a></li>" % (self.params.urlencode(), i)
66             page_html_list.append(temp)
67         if self.current_page_num>=self.all_pager:
68             next_page="<li class='disabled'><a href='#'>下一页</a></li>"
69         else:
70             next_page = "<li ><a href='?page=%s'>下一页</a></li>" % (self.current_page_num+1)
71         page_html_list.append(next_page)
72         last_page = '<li><a href="?page=%s">尾页</li>' % (self.all_pager)
73         page_html_list.append(last_page)
74         return "".join(page_html_list)

4.index视图函数

1 from django.shortcuts import render
2 from app01.models import Book
3 def index(request):
4     from app01.page import Pagination
5     current_page_num = request.GET.get("page")
6     book_list = Book.objects.all()
7     pagination=Pagination(current_page_num,book_list.count(),request)
8     booklist=book_list[pagination.start:pagination.end]
9     return render(request,"index.html",locals())

5.index.html页面

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
 7 
 8 </head>
 9 <body>
10 <ul>
11     {% for book in booklist %}
12     <li>名称:{{ book.title }} 价格:{{ book.price }}</li>
13     {% endfor %}
14 <nav aria-label="Page navigation">
15   <ul class="pagination">
16    {{ pagination.page_html|safe }}
17   </ul>
18 </nav>
19 </ul>
20 </body>
21 </html>

.保存搜索条件

1.原码部分:

为什么request.get得到的queryset不能更改,但是copy之后的queryset可以更改

 1 class QueryDict(MultiValueDict):
 2 
 3 _mutable = True
 4 
 5 #mutable是可更改的意思,默认为true,可以更改
 6 _encoding = None
 7 def __init__(self, query_string=None, mutable=False, encoding=None):
 8 
 9 Pass#当实例化方法执行之后mutable更改为False,不可以更改
10 
11    def __copy__(self):
12        result = self.__class__('', mutable=True, encoding=self.encoding)
13        for key, value in self.lists():
14           result.setlist(key, value)
15        return result
16     def __deepcopy__(self, memo):
17        result = self.__class__('', mutable=True, encoding=self.encoding)
18        memo[id(self)] = result
19        for key, value in self.lists():
20            result.setlist(copy.deepcopy(key, memo), copy.deepcopy(value, memo))
21        return result
22 
23 #当执行深拷贝或浅拷贝方法时,mutable又被更改为true,可以更改

2.urlencode()方法

  拷贝之后可以使用urlencode方法

  params=copy.deepcopy(request.GET)

  print(params.urlencode())

  得到的是搜索条件没有拆包urlencode模式: page=10&a=1

3.保存搜索条件的方法

(1)调用该类时,request传进去

pagination=Pagination(current_page_num,book_list.count(),request)

(2)在实例化时深拷贝request.GET

import copy
self.params = copy.deepcopy(request.GET)

(3)将搜索条件全都放到parmas字典中,利用urlencode方法,拼接成路径的urlencode模式,并放到相应的位置

1 for i in range(page_start,page_end):
2     self.params["page"]=i
3     if i==self.current_page_num:
4         temp="<li class='active'><a href='?%s'>%s</a></li>" % (self.params.urlencode(),i)
5     else:
6         temp = "<li><a href='?%s'>%s</a></li>" % (self.params.urlencode(), i)
7     page_html_list.append(temp)

.CBV

FBV:function based view,基于函数的视图

CBV:class based view,基于类的视图

1.cbv流程

(1)在视图类创建视图类

 1 from django.shortcuts import render,HttpResponse
 2 from django.views import View
 3 class LoginView(View):
 4     def get(self,request):
 5         return render(request,"login.html")
 6     def post(self,request):
 7         print("post")
 8         return HttpResponse("ok")
 9     def delete(self,request):
10         pass
11     def put(self,request):
12         pass

(2) urls.py中为该类创建相应的分支

path('login/', views.LoginView.as_view()),

(3)创建视图类中需要的HTML

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <form action="" method="post">
 9     {% csrf_token %}
10     用户名: <input type="text" name="user">
11     密码: <input type="text" name="pwd">
12     <input type="submit">
13 </form>
14 </body>
15 </html>2.原码部分

2.原码部分

(1)View中的as_view

 1 @classonlymethod
 2 
 3 def as_view(cls, **initkwargs):
 4 
 5 #cls代表当前类
 6     for key in initkwargs:
 7         if key in cls.http_method_names:
 8             raise TypeError("You tried to pass in the %s method name as a "
 9                             "keyword argument to %s(). Don't do that."
10                             % (key, cls.__name__))
11         if not hasattr(cls, key):
12             raise TypeError("%s() received an invalid keyword %r. as_view "
13                             "only accepts arguments that are already "
14                             "attributes of the class." % (cls.__name__, key))
15 
16     def view(request, *args, **kwargs):
17         self = cls(**initkwargs)
18 
19 #self代表LoginView的实例对象
20         if hasattr(self, 'get') and not hasattr(self, 'head'):
21             self.head = self.get
22         self.request = request
23         self.args = args
24         self.kwargs = kwargs
25         return self.dispatch(request, *args, **kwargs)
26 
27 #分发方法
28     view.view_class = cls
29     view.view_initkwargs = initkwargs
30 
31     update_wrapper(view, cls, updated=())
32 
33     update_wrapper(view, cls.dispatch, assigned=())
34     return view

(3) dispatch()

 1 def dispatch(self, request, *args, **kwargs):
 2     if request.method.lower() in self.http_method_names:
 3 
 4 #判断request.mothod是否在self.http_method_names中
 5 
 6 #http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
 7 
 8 #http协议中主要支持的请求方式
 9         handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
10 
11 #利用反射去LoginView中找其中的某个方法(get)
12     else:
13         handler = self.http_method_not_allowed
14     return handler(request, *args, **kwargs)
15 
16 #执行了找到的那个方法(get)

 

 

原文地址:https://www.cnblogs.com/shanghongyun/p/9918183.html