分页组件与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)
改变世界,改变自己!