志不坚者智不达。
主要内容:Django分页、自定义simpletag、权限管理
Django分页
Django自带了一个分页功能,使用起来很方便。官方文档
先来看一下效果图:
后台代码:
def customers(request): customers_set = models.Customer.objects.all() # 生成分页实例,第一个参数为query_set对象,第二个参数为每页显示多少条数据 paginator = Paginator(customers_set, 1) # 从请求中获取页码 page = request.GET.get("page") try: customers_iter = paginator.page(page) # 如果获取的page不是数字,就默认返回第一页 except PageNotAnInteger: customers_iter = paginator.page(1) # 如果获取的page不存在,就默认返回最后一页 except EmptyPage: customers_iter = paginator.page(paginator.num_pages) return render(request, "crm/customers.html", {"customers": customers_iter})
前端代码:
<nav> <ul class="pagination"> {% if customers.has_previous %} <li class=""> <a href="?page={{ customers.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% else %} <li class="disabled"> <a href="" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% endif %} {% for page in customers.paginator.page_range %} {% if page == customers.number %} <li class="active"><a href="?page={{ page }}">{{ page }}</a></li> {% else %} <li class=""><a href="?page={{ page }}">{{ page }}</a></li> {% endif %} {% endfor %} {% if customers.has_next %} <li class=""> <a href="?page={{ customers.next_page_number }}" aria-label="Previous"> <span aria-hidden="true">»</span> </a> </li> {% else %} <li class="disabled"> <a href="" aria-label="Previous"> <span aria-hidden="true">»</span> </a> </li> {% endif %} </ul> </nav>
这个方法默认会把所有的页数显示出来,这就会有一个问题就是如果页数特别多显示出来就不好看了。
所有还要优化一下,如下图:
前端代码:
<nav> <ul class="pagination"> {% if customers.has_previous %} <li class=""><a href="?page={{ customers.previous_page_number }}" aria-label="Previous"><span aria-hidden="true">«</span></a></li> {% else %} <li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">«</span></a></li> {% endif %} {% for page in customers.paginator.page_range %} {% get_show_pages customers.number page %} {% endfor %} {% if customers.has_next %} <li class=""><a href="?page={{ customers.next_page_number }}" aria-label="Previous"><span aria-hidden="true">»</span></a></li> {% else %} <li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">»</span></a></li> {% endif %} </ul> </nav>
这里就用到了一个自定义的simpletag:
get_show_pages.py
#! /usr/bin/env python # -*- coding: utf-8 -*- # __author__ = "Q1mi" # Email: master@liwenzhou.com from django import template from django.utils.html import format_html register = template.Library() @register.filter def value_upper(val): return val.upper() # 获得需要展示的页码数 @register.simple_tag def get_show_pages(current_page, loop_num): offset = abs(current_page - loop_num) # 只显示当前页前后三页的页码数 if offset < 3: if current_page == loop_num: page_str = '<li class="active"><a href="?page={}">{}</a></li>'.format(loop_num, loop_num) else: page_str = '<li class=""><a href="?page={}">{}</a></li>'.format(loop_num, loop_num) return format_html(page_str) else: return ""
当然还可以用一个simpletag直接完成整个分页的前端展示功能。
#! /usr/bin/env python # -*- coding: utf-8 -*- # __author__ = "Q1mi" # Email: master@liwenzhou.com from django import template from django.utils.html import format_html register = template.Library() # 直接把整个分页功能写成一个单独的simple_tag,方便复用 @register.simple_tag def show_pages(obj, show_num): """ 自定义的一个分页功能 :param obj: paginator对象 :param show_num: 当前页前后要显示的页码数 :return: """ global previous_page_str global next_page_str show_pages_str = '' if obj.has_previous(): # 如果有上一页就显示左<<标志可点 previous_page_str = ''' <li class=""> <a href="?page={}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li>'''.format(obj.previous_page_number()) else: # 没有上一页就给li标签添加一个disabled class,即显示<<不可点击 previous_page_str = ''' <li class="disabled"> <a href="" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li>''' for page in obj.paginator.page_range: # 便利页码 if abs(obj.number - page) < show_num: # 如果在要显示的范围内 if obj.number == page: # 如果是当前页,就给当前的li标签添加一个active的class show_pages_str += ''' <li class="active"> <a href="?page={}">{}</a> </li> '''.format(page, page) else: # 否则li标签就不加active show_pages_str += ''' <li class=""> <a href="?page={}">{}</a> </li>'''.format(page, page) if obj.has_next(): # 如果有下一页 next_page_str = ''' <li class=""> <a href="?page={}" aria-label="Previous"> <span aria-hidden="true">»</span> </a> </li>'''.format(obj.next_page_number()) else: # 没有下一页,就给li标签加一个disabled的class next_page_str = ''' <li class="disabled"> <a href="" aria-label="Previous"> <span aria-hidden="true">»</span> </a> </li>''' html_str = "{}{}{}".format(previous_page_str, show_pages_str, next_page_str) # 得到整个html字符串 return format_html(html_str) # 渲染返回给前端
simpletag实现一个独立的分页
自定义template tags
自定义的template tags 用于扩展Django 模板的功能。官方文档
首先要使用自定义的template tags就需要在app下,建一个与models.py和views.py同级的templatetags模块,在这个模块下写自定义的simple tag py文件。
其次在使用该自定义simple tag的模板中,使用{% load xxx %}导入自定义的simple tag:xxx,引用的时候直接写xxx.py内的定义的方法名即可。
template filters
一个最简单的例子,返回变量的大写:
from django import template register = template.Library() @register.filter def value_upper(val): return val.upper()
在前端使用 {{ your_value | value_upper }}就可以把your_value变成大写了。
当然还有stringfilter等,可以查看官方文档。
simple tags
simple tag 能实现的功能就比较复杂了。
from django import template from django.utils.html import format_html register = template.Library() # 获得需要展示的页码数 @register.simple_tag def get_show_pages(current_page, loop_num): offset = abs(current_page - loop_num) # 只显示当前页前后三页的页码数 if offset < 3: if current_page == loop_num: page_str = '<li class="active"><a href="?page={}">{}</a></li>'.format(loop_num, loop_num) else: page_str = '<li class=""><a href="?page={}">{}</a></li>'.format(loop_num, loop_num) return format_html(page_str) else: return ""
一个simple tag例子
Django 1.9中新增了一个很NB的功能就是在前端赋值变量,即使用as语法来给一个变量赋值。
这里补充一个url的方法,用于在前端生成url。
我们可以在urls.py里面给url增加一个name="xxx"(相当于起个别名,在别处可以调用这条url的匹配关系),然后在前端调用这个方法。
如果url有正则命名的分组,那么在前端在调用url时,必须给指定参数(正则的组)传值。
urls.py:
urlpatterns = [ url(r'^(?P<word1>\w+)/(?P<word2>\w+)/from/Q1mi/$', views.url_name_test, name="url_name_test"), ]
前端:
<div style="margin: auto"> <p>{% url "url_name_test" word1="hello" word2="world" %}</p> {% url "url_name_test" word1="hello" word2="world" as url_value %} <p>{{ url_value | value_upper }} </p> </div>
网页:
/hello/world/from/Q1mi/ /HELLO/WORLD/FROM/Q1MI/
附老外的解答:
权限管理
django自带有基本的权限管理 ,但粒度和限制权限的维度都只是针对具体的表,如果我们想根据业务功能来限制权限,那就得自己写了,不过也不用完全自己的写,我们可以在django 自带的权限基础上轻松的实现扩展。
想对一个功能实现权限控制,要做到只能过在views类或方法上加一个装饰器就行。