实战Django:Rango Part6

24.优化模板



在这个项目中,从已经做过的模板来看,你可能会注意到里面有很多重复的代码。这种重复不仅带来大量无谓的工作量,而且以后调整起来也极为不便。

因此,最理想的做法是将那些重复的代码放到基础模板中,然后从基础模板再扩展出一个个新的模板。

我们先来做这个基础模板,在templates/rango文件夹下新建一个base.html文件,然后添加以下内容:

templates/rango/base.html

<!DOCTYPE html>

<html>
    <head>
        <title>Rango - {% block title %}实战Django!{% endblock %}</title>
    </head>

    <body>
        <div>
            {% block body_block %}{% endblock %}
        </div>

        <hr />

        <div>
            <ul>
            {% if user.is_authenticated %}
                <li><a href="/rango/restricted/">限制页面</a></li>
                <li><a href="/rango/logout/">注销</a></li>
                <li><a href="/rango/add_category/">新建分类</a></li>
            {% else %}
                <li><a href="/rango/register/">注册</a></li>
                <li><a href="/rango/login/">登录</a></li>
            {% endif %}

                <li><a href="/rango/about/">关于</a></li>
            </ul>
        </div>
    </body>
</html>

我们来修改一下category.html这个模板,把内容改成下面这样:

templates/rango/category.html

{% extends ‘rango/base.html‘ %}

{% load staticfiles %}

{% block title %}{{ category_name }}{% endblock %}

{% block body_block %}
    <h1>{{ category_name }}</h1>
    {% if category %}
        {% if pages %}
        <ul>
                {% for page in pages %}
                <li><a href="{{ page.url }}">{{ page.title }}</a></li>
                {% endfor %}
                </ul>
        {% else %}
                <strong>当前分类下尚无可用页面!</strong>
                {% endif %}

        {% if user.is_authenticated %}
                <a href="/rango/category/{{category.slug}}/add_page/">添加页面</a>
                {% endif %}
        {% else %}
            指定的分类名称 {{ category_name }} 不存在!
    {% endif %}

{% endblock %}

注意,我们在第一行中写了一句”{% extends ‘rango/base.html‘ %} “,它表示本模板继承了base.html这个模板,这样我们在这个模板中就只需专注添加”block title“和”body_block “这两块就行!

我们可以用同样的方式对其它的模板进行处理。

在基础模板中,我们还可以直接引用url的名称。比如“关于”页面的链接,原来写的是:“

  • <a href="/rango/about/">关于
  • ”,我们可以改成这样:

    templates/rango/base.html

    <li><a href="{% url ‘about‘ %}">关于</a></li>

    当程序看到“{% url …}”的时候,它会自动去urls.py文件中找相应的名称(比如说”about”).这样写的好处是,以后当我们要修改链接时,不必去逐个改动模板,而只要在urls.py中进行修改就可以了!

    ”关于“这个页面的链接我们还可以这样写:

    <li><a href="{% url ‘rango.views.about‘ %}">关于</a></li>

    这相当于告诉程序,到”rango”这个应用中,找一个叫”about”的视图。不过我还是更喜欢前面一种写法。

    我们可以将base.html模板中的那些链接写成这样:

    templates/rango/base.html(更新</body>前面的最后一个<div>标签里的内容)

    <div>
            <ul>
        {% if user.is_authenticated %}
            <li><a href="{% url ‘restricted‘ %}">限制页面</a></li>
            <li><a href="{% url ‘logout‘ %}">注销</a></li>
            <li><a href="{% url ‘add_category‘ %}">新建分类</a></li>
        {% else %}
            <li><a href="{% url ‘register‘ %}">注册</a></li>
            <li><a href="{% url ‘login‘ %}">登录</a></li>
        {% endif %}
    
        <li><a href="{% url ‘about‘ %}">关于</a></li>
        </ul>
    </div>

    我们再来看看首页模板,在index.html中,我们可以用同样的方式来改造。

    比如category的链接,我们可以写成:

    templates/rango/index.html(找不到么?用第一行代码搜索一下!):

                    {% for category in categories %}
                    <!-- 下面这行给分类加入了超链接 -->
                    <li><a href="{% url ‘category‘  category.slug %}">{{ category.name }}</a></li>
                    {% endfor %}

    你可以尝试将所有的链接都改写过来,舍得建议大家一开始就养成这样写的习惯。

    25.Cookies(信息指纹)和Sessions(会话)



    Cookies和Sessions在当今的网络应用程序中是极为重要的。事实上在之前我们讲到登录和注销的模块时,我们已经用到了Cookies和Sessions,只不过没告诉你罢了。现在我们来看看Cookies和Sessions在其它方面的应用。

    先来段测试。找到rango/views.py,在index视图的第一行插入如下代码:

    rango/views.py

    request.session.set_test_cookie()

    然后找到register视图,在第一行插入下面三行代码:

    if request.session.test_cookie_worked():
            print (">>>> TEST COOKIE WORKED!")
            request.session.delete_test_cookie()

    加完上面这些代码(注意缩进哦),在浏览器的地址栏中输入:

    http://127.0.0.1:8000/rango/

    然后点击”注册“链接,你应该可以在你的Django服务器控制台(Dos命令提示符下,还记得执行”python manage.py runserver”的地方不?)下看到如下的字样:

    >>>> TEST COOKIE WORKED!

    如果看不到,可能是你的浏览器中禁用了Cookies。

    好了,刚才只是一个测试,现在你可以删掉添加那几行代码,继续往下看。

    我们知道cookies已经能正常工作了,让我们来做一个非常简单的站点访问数统计。要实现这项功能,我们需要做两个cookies,一个用来记录用户访问Rango的次数,另一个则用来记录用户上一次访问Rango的时间,第二个cookies可以帮助我们统计那些一天内频繁访问Rango的用户,不管他一天访问多少次,我们只算他一次的访问量。

    编辑rango/views.py,修改index视图:

    rango/views.py

    def index(request):
    
        category_list = Category.objects.all()
        page_list = Page.objects.order_by(‘-views‘)[:5]
        context_dict = {‘categories‘: category_list, ‘pages‘: page_list}
    
        # 获取站点的访问量
        # 我们用COOKIES.get()方法来获取cookie中的访问数据
        # 如果cookie存在,则把返回的数值转成整数
        # 如果cookie不存在,则将visits值设定为0
        visits = int(request.COOKIES.get(‘visits‘, ‘0‘))
    
        reset_last_visit_time = False
    
        # cookie中有last_visit这个值吗?
        if ‘last_visit‘ in request.COOKIES:
            # 好滴,果然有这个值
            last_visit = request.COOKIES[‘last_visit‘]
            # 将这个值用python的datetime库转换为特定的日期格式
            last_visit_time = datetime.strptime(last_visit[:-7], "%Y-%m-%d %H:%M:%S")
    
            # 如果从上次登录到现在已经超过一天,则访问数加1...
            if (datetime.now() - last_visit_time).days > 0:
                visits = visits + 1
                # ...将重置last_visit时间的信号设为True,表示此值需要更新
                reset_last_visit_time = True
        else:
            # Cookie中没有last_visit值, 也将重置last_visit时间的信号设为True
            reset_last_visit_time = True
    
            context_dict[‘visits‘] = visits
    
        # 先渲染出response对象,以便增加cookie信息
        response = render(request, ‘rango/index.html‘, context_dict)
        if reset_last_visit_time:
            response.set_cookie(‘last_visit‘, datetime.now())
        response.set_cookie(‘visits‘, visits)
    
        # 将response对象返回给用户,更新需更改的cookie值
        return response

    因为我们这里用到了Python的datetime库,别忘了在文件头部加入这样一句:

    from datetime import datetime

    我们来看一下效果,在谷歌浏览器(chrome)中输入:http://127.0.0.1:8000/rango/,首页出现了。

    如果想看到访问数据,需要做以下几步操作:

    • 在浏览器窗口空白处点击右键,从弹出的快捷菜单中选择“审查元素”;
    • 转到下方的”Resources“选项卡;
    • 从左下方找到”Cookies“项中的”127.0.0.1“,这样就能看到访问数(visits)了;

    如果visits数据为0,不妨修改一下系统时间(改到明天即可),然后再刷新浏览器的页面,你就可以观察到数据的变化了。

    上面这个例子的访问数据是储存在用户的电脑上的,然而,更安全也更常用的做法是将会话信息储存到服务器上。

    要使用基于cookie的会话,你需要检查一下Rango的环境:

    • 保证settings.py中的MIDDLEWARE_CLASSES配置中有“django.contrib.sessions.middleware.SessionMiddleware”这一句;
    • 保证settings.py中的INSTALLED_APPS配置中有“django.contrib.sessions”这一句;

    如果你在前面一步步做下来,那么这两项都应该符合要求的。

    我们再来编辑rango/views.py,修改index视图:

    rango/views.py

    def index(request):
    
        category_list = Category.objects.order_by(‘-likes‘)[:5]
        page_list = Page.objects.order_by(‘-views‘)[:5]
    
        context_dict = {‘categories‘: category_list, ‘pages‘: page_list}
    
        visits = request.session.get(‘visits‘)
            if not visits:
                visits = 0
        reset_last_visit_time = False
    
        last_visit = request.session.get(‘last_visit‘)
        if last_visit:
            last_visit_time = datetime.strptime(last_visit[:-7], "%Y-%m-%d %H:%M:%S")
            if (datetime.now() - last_visit_time).seconds > 0:
                # ...访问数加1...
                visits = visits + 1
                # ...发出更新last_visit值的信号
                reset_last_visit_time = True
        else:
            # last_visit值不存在,发出创建last_visit值的信号.
            reset_last_visit_time = True
    
        context_dict[‘visits‘] = visits
        request.session[‘visits‘] = visits
        if reset_last_visit_time:
            request.session[‘last_visit‘] = str(datetime.now())
    
        response = render(request,‘rango/index.html‘, context_dict)
    
        return response

    【未完待续】

    本文版权归舍得学苑所有,欢迎转载,转载请注明作者和出处。谢谢!

    作者:舍得

    首发:舍得学苑@博客园

     
    时间: 2024-08-07 00:14:12

    实战Django:Rango Part6的相关文章

    实战Django:Rango Part1

    在前面我们已经陆续学习了六个Django的实例,其中一个来自Django官方的文档,另外五个来自<Django Web开发指南>.舍得介绍的每一个实例,都是按照官方文档的标准,力求让大家在根据文章去做自己的实例时,能够按"文"索骥,轻松再现整个实例的制作过程. 接下来,舍得要介绍一个大型的实例,这个项目叫做Rango,它来自Django圈内口碑甚佳的<How to Tango with Django>一书.事实上,此书就是围绕Rango这一个实例来展开的,而且,

    实战Django:Rango Part7

    26.用Django-Registration-Redux进行用户校验 Django中,有好多现成的应用提供了注册.登录.校验等功能,我们只要稍稍改动一下URL映射.视图和模板就可以使用它们.在这一章,我们将介绍用Django-Registration-Redux,顺便学习一下如何把外部的应用加到我们的项目中. (1)安装Django-Registration-Redux 在Dos命令提示符下转到Python的Scripts文件夹,然后运行如下命令: pip install django-reg

    实战Django:简易博客Part1

    舍得学习新技能的时候,通常不喜欢傻读书--捧着一本阐述该项技能的书籍,然后傻看,一路看下来,脑子里塞满了新的概念.知识点,头是越来越大,但技能却几乎没掌握半分. 多年来,舍得养成了用做实例来学习新技能的习惯.这可不是舍得的独创,在象棋.围棋界中,历来有"打谱"一说,就是根据棋谱,把一步步棋摆出来,在打谱的过程中,去感悟.去吸收,此时感悟到的.吸收进的,才是属于你自己的东西.新的技能就这样一步步发展起来,逐渐壮大. 就象Django官方文档那样,一个实例看起来很简单,但作为初学者,用&q

    实战Django:简易博客Part2

    在Part1中,我们完成了本项目的基本框架搭建,并完善了一下管理后台,现在我们来看如何设计面向公共的页面部分. 8.创建模板 首先,请在blog文件夹下建立templates文件夹,然后,在templates文件夹中建立一个叫bog的文件夹,在这个bog文件夹下新建一个archive.html文件,这个文件的路径应该是: bog/templates/bog/archive.html 把下面这些代码添加到archive.html中: bog/templates/bog/archive.html:

    实战Django:小型CMS Part2

    回顾一下我们之前讲过的几个实例的流程,现在,我们只要添加一些内容(用来测试),创建视图.模板和URL模式,就能完成这个小型的CMS了.   7.添加内容 我们先来创建一个分类,点击Categories后面的"增加"按钮,然后在Label文本框中输入:"Django",在slug文本框后面输入"django"(django不用输入也能自动出现,你可以改成自己喜欢的名字): 随后点击后面的"保存"按钮. 点击左上方的"首

    实战Django:Pastebin

      这是<Django Web开发指南>中的最后一个实例.如果说上一个实例Liveblog重点讲的是Django和Ajax的协作,那么我们在Pastebin中,将学习到Django和高亮语法JS的协作,顺便复习一下在Django中加入表单. 1.创建项目和应用 我们先来创建本实例的项目,在dos命令提示符下转到Scripts文件夹(如"c:\python32\Scripts"),然后运行如下命令: $ django-admin startproject pastebinpr

    实战Django:官方实例Part1

    [写在前面] 撰写这个实战系列的Django文章,是很久之前就有的想法,问题是手头实例太少,一旦开讲,恐有"无米下锅"之忧. 随着对Django学习的深入,渐渐有了些心得,把这些心得整理出来,以规范的.方便新人上手的撰写方式来写这个实战系列,相信对刚接触Django的童鞋会有一定的帮助. 舍得这里所用到的版本,为Django 1.7.1,Python 3.2,想要按照舍得讲解的实例上手练习的话,请务必与舍得所用的版本保持一致. 实例是在Windows系统下调试的,如果你采用的是非Win

    实战Django:小型CMS Part1

    CMS,即Content Management System,内容管理系统.我们这里要开发的小型CMS应用,从结构上和blog应用有些类似,但我们会在这里加入一些新的技术,比如说工作流.搜索功能.编辑组件等. 1.创建项目和应用 我们先来创建本实例的项目,在dos命令提示符下转到Scripts文件夹(如"c:\python32\Scripts"),然后运行如下命令: $ django-admin startproject cmsproject 然后在dos命令提示符下继续输入如下命令,

    实战Django:LiveBlog

    <Django Web开发指南>的实例讲的差不多了,除了今天要介绍的LiveBlog,还有一个Pastebin.这样,书中的实例基本讲完了.做完这些实例之后,舍得建议回头看看这本书,或许你会从书中找到舍得所讲的实例里忽略掉的一些细节.此外,<Django Web开发指南>中有几个章节是关于Django的基础或高级技术的,建议阅读并设法把它应用到你所练习过的实例中. 正如你已经看到的,Django提供了丰富的内置功能,你可以很轻松地用这些功能来完成很多工作.但和所有的工具一样,Dja