志不坚者智不达。

主要内容: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">&laquo;</span>
            </a>
        </li>
    {% else %}
        <li class="disabled">
            <a href="" aria-label="Previous">
                <span aria-hidden="true">&laquo;</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">&raquo;</span>
            </a>
        </li>
    {% else %}
        <li class="disabled">
            <a href="" aria-label="Previous">
                <span aria-hidden="true">&raquo;</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">&laquo;</span></a></li>
    {% else %}
    <li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">&laquo;</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">&raquo;</span></a></li>
    {% else %}
    <li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">&raquo;</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">&laquo;</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">&laquo;</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">&raquo;</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">&raquo;</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类或方法上加一个装饰器就行。

Python之路Day19的更多相关文章

  1. Python之路,Day19 - CMDB、CMDB、CMDB

    Python之路,Day19 - CMDB.CMDB.CMDB   本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Restful 规范 资产管理功能开发 浅谈ITIL TIL即IT ...

  2. Python学习路程day19

    Python之路,Day19 - Django 进阶   本节内容 自定义template tags 中间件 CRSF 权限管理 分页 Django分页 https://docs.djangoproj ...

  3. Python之路【第一篇】python基础

    一.python开发 1.开发: 1)高级语言:python .Java .PHP. C#  Go ruby  c++  ===>字节码 2)低级语言:c .汇编 2.语言之间的对比: 1)py ...

  4. Python之路

    Python学习之路 第一天   Python之路,Day1 - Python基础1介绍.基本语法.流程控制              第一天作业第二天   Python之路,Day2 - Pytho ...

  5. python之路 目录

    目录 python python_基础总结1 python由来 字符编码 注释 pyc文件 python变量 导入模块 获取用户输入 流程控制if while python 基础2 编码转换 pych ...

  6. Python之路【第十九篇】:爬虫

    Python之路[第十九篇]:爬虫   网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用 ...

  7. Python之路【第十八篇】:Web框架们

    Python之路[第十八篇]:Web框架们   Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...

  8. Python之路【第十七篇】:Django【进阶篇 】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

  9. Python之路【第十六篇】:Django【基础篇】

    Python之路[第十六篇]:Django[基础篇]   Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...

随机推荐

  1. file_get_contents post数据

    //默认模拟的header头 private function _defaultHeader() { $header = "User-Agent:Mozilla/5.0 (Windows; ...

  2. Highlight On Mouseover Effect With JQuery

    How to get the xpath by clicking an html element How to get the xpath by clicking an html element Qu ...

  3. poj 2728 Desert King(最小比率生成树,迭代法)

    引用别人的解释: 题意:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可, 建造水管距离为坐标之间的欧几里德距离(好象是叫欧几里德距离吧),费用为海拔之差 现在要求 ...

  4. 我的IOS学习之路(三):手势识别器

    在iOS的学习中,对于手势的处理是极为重要的,如对于图片,我们经常需要进行旋转,缩放以及移动等.这里做一下总结,详见代码. - (void)viewDidLoad { [super viewDidLo ...

  5. iOS实践02

    第二天了,上了一天课,软件测试.数据挖掘.概率论,晚上了才有时间捣鼓捣鼓程序. 今天只是简单的做了一点.觉得自己思考的写不出来,只能简单的写一个过程,不像第一次写这个,少了很多思考的. 1.完善tab ...

  6. BZOJ 1221: [HNOI2001] 软件开发(最小费用最大流)

    不知道为什么这么慢.... 费用流,拆点.... --------------------------------------------------------------------------- ...

  7. bzoj 4373: 算术天才⑨与等差数列 hash

    题目链接 题目大意:  给你n个数, 给两种操作, 一种给你l, r, k,问你[l, r]区间里的数排序后能否构成一个公差为k的等差数列. 另一种是将位置x的数变为y. 强制在线. 可以用hash来 ...

  8. codeforces 622F. The Sum of the k-th Powers 拉格朗日插值法

    题目链接 求sigma(i : 1 to n)i^k. 为了做这个题这两天真是补了不少数论, 之前连乘法逆元都不知道... 关于拉格朗日插值法, 我是看的这里http://www.guokr.com/ ...

  9. 在Linux中创建静态库和动态库 (转)

    我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为静态库和动态库两种.静态 库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而 ...

  10. ASP.NET 使用My97DatePicker日期控件

    首先要下载该控件的包,下载地址:http://pan.baidu.com/s/1Aa5gk 引用文件 <script src="js/My97DatePicker/WdatePicke ...