Django分页功能和中间件
分页
自定义分页
def booklist(request): # 查看所有书籍信息 books = models.Book.objects.all() # 书籍的数量 books_count = books.count() # 获取url中page 参数 current_page = request.GET.get("page") try: current_page = int(current_page) except Exception as e: current_page = 1 # 允许每页显示多少条数据,此处为10条 per_page = 10 # 页码最多显示多少个页码 max_show = 9 # 最多显示页码数一半, / 结果显示浮点数 , // 结果显示整数 half_show = max_show // 2 # 计算当前数据需要显示多少页 page_count,more = divmod(books_count,per_page) if more: page_count += 1 if current_page > page_count: current_page = page_count # 计算显示页码的起点和终点 show_page_start = current_page - half_show show_page_end = current_page + half_show # 特殊判断,当前页码 - half_show <= 0 时 if current_page - half_show <= 0: show_page_start = 1 show_page_end = max_show # 当前页码 + half_show >= page_count if current_page + half_show > page_count: show_page_start = page_count - max_show+1 show_page_end = page_count # 总共需要的页码数 < max_show if page_count < max_show: show_page_start = 1 show_page_end = page_count # 每页数据的起始和终止点 page_start = (current_page - 1) * per_page page_end = current_page * per_page # 显示每页显示的数据 data = books[page_start:page_end] ''' <nav aria-label="Page navigation"> <ul class="pagination"> # <li> # <a href="#" aria-label="Previous"> # <span aria-hidden="true">«</span> # </a> # </li> <li><a href="#">1</a></li> # <li> # <a href="#" aria-label="Next"> # <span aria-hidden="true">»</span> # </a> # </li> </ul> </nav> ''' tmp = [] page_html_start = '<nav aria-label="Page navigation" class="text-center"><ul class="pagination">' page_html_end = '</ul></nav>' tmp.append(page_html_start) # 添加一个首页 tmp.append('<li><a href="/bk_list/?page=1">首页</a></li>') # 添加一个上一页 # 当 当前页是第一页,不能点击上一页按钮 if current_page == 1: tmp.append('<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>') else: tmp.append('<li><a href="/bk_list/?page={}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format(current_page - 1)) # for循环添加要展示的页码 for i in range(show_page_start,show_page_end+1): # 如果for循环的当前页码等于当前页码,给L标签添加active if current_page == i: tmp.append('<li class="active"><a href="/bk_list/?page={0}">{0}</a></li>'.format(i)) else: tmp.append('<li><a href="/bk_list/?page={0}">{0}</a></li>'.format(i)) #添加一个下一页 # 当 当前页是最后一页,不能点击下一页按钮 if current_page == page_count: tmp.append('<li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li>') else: tmp.append('<li><a href="/bk_list/?page={}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format(current_page + 1)) # 添加一个尾页 tmp.append('<li><a href="/bk_list/?page={}">尾页</a></li>'.format(page_count)) tmp.append(page_html_end) page_html = ''.join(tmp)
class MyPage(object): def __init__(self,current_page,books_count, url_prefix, per_page=10, max_show=9): ''' 初始化一个自定义的分页实例 :param books_count:总的数据量 :param per_page:每一个显示多少条数据 :param url_prefix:分页中a标签的url :param max_show:页面上最多显示多少个页码 ''' self.current_page = current_page self.books_count = books_count self.url_prefix = url_prefix self.per_page = per_page self.max_show = max_show # 获取url中page 参数 # current_page = request.GET.get("page") try: current_page = int(current_page) except Exception as e: current_page = 1 # 允许每页显示多少条数据,此处为10条 per_page = 10 # 页码最多显示多少个页码 max_show = 9 # 最多显示页码数一半, / 结果显示浮点数 , // 结果显示整数 half_show = max_show // 2 # 计算当前数据需要显示多少页 page_count, more = divmod(books_count, per_page) if more: page_count += 1 if current_page > page_count: current_page = page_count self.current_page = current_page self.page_count = page_count # 计算显示页码的起点和终点 show_page_start = current_page - half_show show_page_end = current_page + half_show # 特殊判断,当前页码 - half_show <= 0 时 if current_page - half_show <= 0: show_page_start = 1 show_page_end = max_show # 当前页码 + half_show >= page_count if current_page + half_show >= page_count: show_page_start = page_count - max_show + 1 show_page_end = page_count # 总共需要的页码数 < max_show if page_count < max_show: show_page_start = 1 show_page_end = page_count self.show_page_start = show_page_start self.show_page_end = show_page_end @property def start(self): # 每页数据的起始和终止点 return (self.current_page - 1) * self.per_page @property def end(self): return self.current_page * self.per_page # 分页html 代码 def page_html(self): tmp = [] page_html_start = '<nav aria-label="Page navigation" class="text-center"><ul class="pagination">' page_html_end = '</ul></nav>' tmp.append(page_html_start) # 添加一个首页 tmp.append('<li><a href="/{}/?page=1">首页</a></li>'.format(self.url_prefix)) # 添加一个上一页 # 当 当前页是第一页,不能点击上一页按钮 if self.current_page == 1: tmp.append( '<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>') else: tmp.append('<li><a href="/{1}/?page={0}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format(self.current_page - 1,self.url_prefix)) # for循环添加要展示的页码 for i in range(self.show_page_start, self.show_page_end + 1): # 如果for循环的当前页码等于当前页码,给L标签添加active if self.current_page == i: tmp.append('<li class="active"><a href="/bk_list/?page={0}">{0}</a></li>'.format(i)) else: tmp.append('<li><a href="/{1}/?page={0}">{0}</a></li>'.format(i,self.url_prefix)) # 添加一个下一页 # 当 当前页是最后一页,不能点击下一页按钮 if self.current_page == self.page_count: print('current_page=======',self.current_page) print('page_count=======', self.page_count) tmp.append('<li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li>') else: tmp.append('<li><a href="/{1}/?page={0}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format(self.current_page + 1,self.url_prefix)) # 添加一个尾页 tmp.append('<li><a href="/{1}/?page={0}">尾页</a></li>'.format(self.page_count,self.url_prefix)) tmp.append(page_html_end) page_html = ''.join(tmp) return page_html
def booklist(request): # 查看所有书籍信息 books = models.Book.objects.all() # 书籍的数量 books_count = books.count() current_page = request.GET.get("page") # url_prefix = request.path_info page_obj = mypage.MyPage(current_page,books_count,url_prefix="bk_list") # 显示每页显示的数据 data = books[page_obj.start:page_obj.end] page_html = page_obj.page_html() return render(request,'booklist.html',{'books':data,'page_html':page_html})
Django内置分页
from django.shortcuts import render from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger L = [] for i in range(999): L.append(i) def index(request): current_page = request.GET.get('p') paginator = Paginator(L, 10) # per_page: 每页显示条目数量 # count: 数据总个数 # num_pages:总页数 # page_range:总页数的索引范围,如: (1,10),(1,200) # page: page对象 try: posts = paginator.page(current_page) # has_next 是否有下一页 # next_page_number 下一页页码 # has_previous 是否有上一页 # previous_page_number 上一页页码 # object_list 分页之后的数据列表 # number 当前页 # paginator paginator对象 except PageNotAnInteger: posts = paginator.page(1) except EmptyPage: posts = paginator.page(paginator.num_pages) return render(request, 'index.html', {'posts': posts})
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> {% for item in posts %} <li>{{ item }}</li> {% endfor %} </ul> <div class="pagination"> <span class="step-links"> {% if posts.has_previous %} <a href="?p={{ posts.previous_page_number }}">Previous</a> {% endif %} <span class="current"> Page {{ posts.number }} of {{ posts.paginator.num_pages }}. </span> {% if posts.has_next %} <a href="?p={{ posts.next_page_number }}">Next</a> {% endif %} </span> </div> </body> </html>
中间件
中间件介绍
中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。
但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。
说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定时间去执行这些方法。
自定义中间件
在项目下的app中,写一个中间件的类
from django.utils.deprecation import MiddlewareMixin class RBACMiddleware(MiddlewareMixin): white_list = ['/login/',] black_list = ['/black',] def process_request(self,request): next = request.path_info if next in self.white_list or request.session.get("login"): return None elif next in self.black_list: return HttpResponse('gun') else: return redirect('/login/?next={}'.format(next))
在settings.py中注册中间件
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', ... 'middleware.中间件类名', #中间件注册 ]
中间件的五种用法
中间件可以定义五个方法,分别是(主要是process_request和process_response) 1. process_request(self,request) 2. process_view(self,request,view_func,view_args,view_kwargs) 3. process_template_response(self,request,response) 4. process_exception(self,request,exception) 5. process_response(self,request,response) 以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照Django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户
process_request
主要记忆:执行时间、执行顺序、参数和返回值 1. process_request(self,request) 1. 执行时间 在执行视图函数之前执行 2. 执行顺序 按照注册的顺序执行 3. 参数和返回值 1. request参数和视图函数中是同一个对象 2. 返回值: 1. 返回None:请求继续往后执行 2. 返回响应对象:请求就结束了,要返回响应了
process_response
process_response(self, request, response) 1. 执行时间 视图函数执行之后(拿到响应对象之后) 2. 执行顺序 按照注册的倒序执行 3. 参数和返回值 1. 参数:request请求对象 response:响应对象 2. 返回值: 只能返回响应对象 1. 返回默认的 2. 自己生成一个响应对象返回
process_view
process_view(self, request, view_func, view_args, view_kwargs) 1. 执行时间 视图函数之前,在urls.py找到将要执行的视图函数之后 2. 执行顺序 注册的顺序执行 3. 参数和返回值 1. 参数: 1. request: 请求对象 2. view_func:将要执行的视图函数 2. 返回值: 1. 返回None:继续往后执行 2. 返回响应对象,直接跳出,按照process_response方法的顺序执行
练习:
限制用户访问频率,一分钟只允许访问3次
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse,render,redirect import time D = {} Whitelist = ['/test/'] class Xianzhi(MiddlewareMixin): def process_request(self,request): # 限制访问频率 # 当前访问ip ip = request.META.get("REMOTE_ADDR") now = time.time() if request.path_info in Whitelist: return None if ip not in D: D[ip] = [] # 拿到当前ip的访问历史记录 history = D[ip] while history and now - history[-1] > 60: history.pop() if len(history) >= 3: return HttpResponse('gun') else: history.insert(0,now)
使用中间件用于登录验证
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'mymiddleware.LoginCheckMD1', ]
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import render,HttpResponse,redirect # 定义一个登陆验证的中间件 class LoginCheckMD1(MiddlewareMixin): white_list = ['/login/',] black_list = ['/black',] def process_request(self,request): next = request.path_info if next in self.white_list or request.session.get("login"): return None elif next in self.black_list: return HttpResponse('gun') else: return redirect('/login/?next={}'.format(next))

浙公网安备 33010602011771号