自定义分页 Cookie Session和获得路径
自定义分页
稳抓稳打版
def publisher_list(request): # 从URL中取当前访问的页码数 try: current_page = int(request.GET.get('page')) except Exception as e: # 取不到或者页码数不是数字都默认展示第1页 current_page = 1 # 总数据量 total_count = models.Publisher.objects.count() # 定义每页显示多少条数据 per_page = 10 # 计算出总页码数 total_page, more = divmod(total_count, per_page) if more: total_page += 1 # 定义页面上最多显示多少页码(为了左右对称,一般设为奇数) max_show = 11 half_show = max_show // 2 # 计算一下页面显示的页码范围 if total_page <= max_show: # 总页码数小于最大显示页码数 page_start = 1 page_end = total_page elif current_page + half_show >= total_page: # 右边越界 page_end = total_page page_start = total_page - max_show elif current_page - half_show <= 1: # 左边越界 page_start = 1 page_end = max_show else: # 正常页码区间 page_start = current_page - half_show page_end = current_page + half_show # 数据索引起始位置 data_start = (current_page-1) * per_page data_end = current_page * per_page publisher_list = models.Publisher.objects.all()[data_start:data_end] # 生成页面上显示的页码 page_html_list = [] page_html_list.append('<nav aria-label="Page navigation"><ul class="pagination">') # 加首页 first_li = '<li><a href="/publisher_list/?page=1">首页</a></li>' page_html_list.append(first_li) # 加上一页 if current_page == 1: prev_li = '<li><a href="#"><span aria-hidden="true">«</span></a></li>' else: prev_li = '<li><a href="/publisher_list/?page={}"><span aria-hidden="true">«</span></a></li>'.format(current_page - 1) page_html_list.append(prev_li) for i in range(page_start, page_end + 1): if i == current_page: li_tag = '<li class="active"><a href="/publisher_list/?page={0}">{0}</a></li>'.format(i) else: li_tag = '<li><a href="/publisher_list/?page={0}">{0}</a></li>'.format(i) page_html_list.append(li_tag) # 加下一页 if current_page == total_page: next_li = '<li><a href="#"><span aria-hidden="true">»</span></a></li>' else: next_li = '<li><a href="/publisher_list/?page={}"><span aria-hidden="true">»</span></a></li>'.format(current_page + 1) page_html_list.append(next_li) # 加尾页 page_end_li = '<li><a href="/publisher_list/?page={}">尾页</a></li>'.format(total_page) page_html_list.append(page_end_li) page_html_list.append('</ul></nav>') page_html = "".join(page_html_list) return render(request, "publisher_list.html", {"publisher_list": publisher_list, "page_html": page_html})
封装保存版
class Pagination(object): """自定义分页(Bootstrap版)""" def __init__(self, current_page, total_count, base_url, per_page=10, max_show=11): """ :param current_page: 当前请求的页码 :param total_count: 总数据量 :param base_url: 请求的URL :param per_page: 每页显示的数据量,默认值为10 :param max_show: 页面上最多显示多少个页码,默认值为11 """ try: self.current_page = int(current_page) except Exception as e: # 取不到或者页码数不是数字都默认展示第1页 self.current_page = 1 # 定义每页显示多少条数据 self.per_page = per_page # 计算出总页码数 total_page, more = divmod(total_count, per_page) if more: total_page += 1 self.total_page = total_page # 定义页面上最多显示多少页码(为了左右对称,一般设为奇数) self.max_show = max_show self.half_show = max_show // 2 self.base_url = base_url @property def start(self): return (self.current_page-1) * self.per_page @property def end(self): return self.current_page * self.per_page def page_html(self): # 计算一下页面显示的页码范围 if self.total_page <= self.max_show: # 总页码数小于最大显示页码数 page_start = 1 page_end = self.total_page elif self.current_page + self.half_show >= self.total_page: # 右边越界 page_end = self.total_page page_start = self.total_page - self.max_show elif self.current_page - self.half_show <= 1: # 左边越界 page_start = 1 page_end = self.max_show else: # 正常页码区间 page_start = self.current_page - self.half_show page_end = self.current_page + self.half_show # 生成页面上显示的页码 page_html_list = [] page_html_list.append('<nav aria-label="Page navigation"><ul class="pagination">') # 加首页 first_li = '<li><a href="{}?page=1">首页</a></li>'.format(self.base_url) page_html_list.append(first_li) # 加上一页 if self.current_page == 1: prev_li = '<li><a href="#"><span aria-hidden="true">«</span></a></li>' else: prev_li = '<li><a href="{}?page={}"><span aria-hidden="true">«</span></a></li>'.format( self.base_url, self.current_page - 1) page_html_list.append(prev_li) for i in range(page_start, page_end + 1): if i == self.current_page: li_tag = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i) else: li_tag = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i) page_html_list.append(li_tag) # 加下一页 if self.current_page == self.total_page: next_li = '<li><a href="#"><span aria-hidden="true">»</span></a></li>' else: next_li = '<li><a href="{}?page={}"><span aria-hidden="true">»</span></a></li>'.format( self.base_url, self.current_page + 1) page_html_list.append(next_li) # 加尾页 page_end_li = '<li><a href="{}?page={}">尾页</a></li>'.format(self.base_url, self.total_page) page_html_list.append(page_end_li) page_html_list.append('</ul></nav>') return "".join(page_html_list) 封装保存版
封装保存版使用示例
def publisher_list(request):
# 从URL中取当前访问的页码数
current_page = int(request.GET.get('page'))
# 比len(models.Publisher.objects.all())更高效
total_count = models.Publisher.objects.count()
page_obj = Pagination(current_page, total_count, request.path_info)
data = models.Publisher.objects.all()[page_obj.start:page_obj.end]
page_html = page_obj.page_html()
return render(request, "publisher_list.html", {"publisher_list": data, "page_html": page_html})
CBV中加装饰器相关
CBV实现的登录视图
class LoginView(View):
def get(self, request):
"""
处理GET请求
"""
return render(request, 'login.html')
def post(self, request):
"""
处理POST请求
"""
user = request.POST.get('user')
pwd = request.POST.get('pwd')
if user == 'alex' and pwd == "alex1234":
next_url = request.GET.get("next")
# 生成随机字符串
# 写浏览器cookie -> session_id: 随机字符串
# 写到服务端session:
# {
# "随机字符串": {'user':'alex'}
# }
request.session['user'] = user
if next_url:
return redirect(next_url)
else:
return redirect('/index/')
return render(request, 'login.html')
要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:
from django.utils.decorators import method_decorator
1. 加在CBV视图的get或post方法上
from django.utils.decorators import method_decorator
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
@method_decorator(check_login)
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
2. 加在dispatch方法上
from django.utils.decorators import method_decorator
class HomeView(View):
@method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。
3. 直接加在视图类上,但method_decorator必须传 name 关键字参数
如果get方法和post方法都需要登录校验的话就写两个装饰器。
from django.utils.decorators import method_decorator
@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
补充
CSRF Token相关装饰器在CBV只能加到dispatch方法上,或者加在视图类上然后name参数指定为dispatch方法。
备注:
1.csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
2.csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
class HomeView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
或者
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt, name='dispatch')
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
Cookie 和 Session
小知识
#request.get_full_path() # 获取当前请求的全路径
#request.path_info # 获取当前请求的路径
2020-04-03