Django Web开发基础(7)使用模板

2019-01-15 08:39:43 织梦安装使用
  • 文章介绍
Python三叔 Python三叔

Tornado框架一样,在Django框架中供了模板功能,通过里面的模板文件分离文档的表现形式和具体内容。在本节的内容中,将详细讲解在Django框架中使用模板的知识。

6.7.1  Django模板的基础用法

Django框架中的模板是静态的HTML文件,它定了一个页面的显示样式或外观。模板需要借助于视图View传递过来的变量(Variable)或内容对象(Context object)才能被渲染成一个完整的页面。这样做的好处是实现了样式与业务逻辑的分离,便于前端和后端Web开发人员各自完成自己的开发工作。

1. Template的工作过程

我们使用一个博客类网站进行举例,当用户访问/blog/article/2/的时候,URL路由器会调用视图文件views.py中的方法article_detail,方法article_detail的功能是提取id=2的文章对象,然后通过方法render将提取到的数据传递到模板文件/blog/article_detail.html。假设URL文件blog/urls.py的对应代码如下所示。

from django.urls import path

 

from . import views

 

urlpatterns = [

  path(blog/article/<int:id>/, views.article_detail, name=article_detail),

]

假设视图文件blog/views.py的对应代码如下所示。

from django.shortcuts import render,get_object_or_404

from .models import Article

 

def article_detail(request, id):

    article= get_object_or_404(Article, pk=id)

    returnrender(request, blog/article_detail.html, {"article": article})

假设下面是模板文件blog/article_detail.html的实现代码。在模板文件中可以通过双括号{{ article }}显示变量或内容对象,还可以通过点号“.”来直接访问变量的属性。

{% block content %}

{{ article.title }}

{{ article.pub_date }}

{{ article.body }}

{% endblock %}

2. 模板(Template)文件的位置

建议读者将HTML格式的模板文件放在app/templates/app/目录中,而不是简单放在app/templates/中。这样从表面看是多加了一层目录使得路径变得复杂化,但是这样实际上会更安全。当我们多加了一层app目录后,Django只会查找app文件夹中的模板文件。在视图文件views.py中也建议通过app/template_name.html调用template,这样会杜绝与其它同名template的冲突。

例如在下面的实例代码中,演示了在Django框架中使用模板的过程。

源码路径:daima66-7zqxt_tmpl

1)分别创建一个名为“zqxt_tmpl”的项目和一个名称为“learn”的应用。

2)将“learn”应用加入到 settings.INSTALLED_APPS中,具体实现代码如下所示。

INSTALLED_APPS = (

   django.contrib.admin,

   django.contrib.auth,

   django.contrib.contenttypes,

   django.contrib.sessions,

   django.contrib.messages,

   django.contrib.staticfiles,

    learn,

)

3)打开文件learn/views.py编写一个首页的视图,具体实现代码如下所示。

from django.shortcuts import render

def home(request):

    returnrender(request, home.html)

4)在“learn”目录下新建一“templates”个文件夹用于保存模板文件,然后在里面新建一个home.html文件作为模板。文件home.html的具体实现代码如下所示。

<!DOCTYPE html>

<html>

<head>

   <title>欢迎光临</title>

</head>

<body>

欢迎选择浪潮产品!

</body>

</html>

5)为了将视图函数对应到网址,对文件zqxt_tmpl/urls.py的代码进行如下所示的修改。

from django.conf.urls import include, url

from django.contrib import admin

from learn import views as learn_views

urlpatterns = [

   url(r^$, learn_views.home, name=home),

   url(r^admin/, admin.site.urls),

]

6)输入如下命令启动服务器:

python manage.py runserver

执行后将显示模板的内容,执行效果如图2-6所示。



2-6  执行效果

6.7.2  模板过滤器Filter

Django框架中,可以通过使用过滤器来改变变量在模板中的显示,例如{{ article.title | lower }}中的过滤器lower可以将文章的标题转化为小写。在Django的模板中提供了许多内置过滤器,具体说明如表6-1所示。

6-1  Django的模板过滤器Filter

过滤器

例子

lower, upper

{{ article.title | lower }} 大小写

length

{{ name | length }} 长度

default

{{ value | default: "0" }} 默认值

date

{{ picture.date | date:"Y-m-j" }} 日期格式

dicsort

{{ value | dicsort: "name" }} 字典排序

escape

{{ title | escape }} 转义

filesizeformat

{{ file | filesizeformat }} 文件大小

first, last

{{ list | first }} 首或尾

floatformat

{{ value | floatformat }} 浮点格式

get_digit

{{ value | get_digit }} 位数

join

{{ list | join: "," }} 字符连接

make_list

{{ value | make_list }} 转字符串

pluralize

{{ number | pluralize }} 复数

random

{{ list | random }} 随机

slice

{{ list | slice: ":2" }}

slugify

{{ title | slugify }} 转为slug

striptags

{{ body | striptags }} 去除tags

time

{{ value | time: "H:i" }} 时间格式

timesince

{{ pub_date | timesince: given_date }}

truncatechars

{{ title | truncatechars: 10 }} 

truncatewords

{{ title | truncatewords: 2 }} 

truncatechars_html

{{ title | truncatechars_html: 2 }}

urlencode

{{ path | urlencode }} URL转义

wordcount
 
 

{{ body | wordcount }} 单词字数

6.7.3  模板标签Tags

Django的模板中,变量被存放在双大括号{{ }}中,代码存放在{% tag_name %}标签中。Django框架中有很多自带标签,可以满足绝大部分开发需求。具体说明如下所示。

1autoescape:控制当前自动转义的行为,有onoff两个选项,例如:

{% autoescape on %}

    {{ body}}

{% endautoescape %}

2block:定义一个子模板可以覆盖的块。

3comment:注释,例如{% comment %} {% endcomment %}之间的内容被解释为注释。

4crsf_token:一个防止CSRF攻击(跨站点请求伪造)的标签。

5cycle:循环给出的字符串或者变量,可以混用。例如:

{% for o in some_list %}

    <trclass="{% cycle row1 rowvalue2 row3 %}">

        ...

   </tr>

{% endfor %}

值得注意的是,这里的变量的值默认不是自动转义的,要么相信你的变量,要么是用强制转义的方法,例如:

{% for o in some_list %}

    <trclass="{% filter force_escape %}{% cycle rowvalue1 rowvalue2 %}{% endfilter%}">

        ...

   </tr>

{% endfor %}

在某些情况下,可能想在循环外部引用循环中的下一个值,这时需要用ascycle标签设置一个名字,这个名字代表的是当前循环的值。但是在cycle标签里面,可以用这个变量来获得循环中的下一个值。例如:

<tr>

    <tdclass="{% cycle row1 row2 as rowcolors %}">...</td>

    <tdclass="{{ rowcolors }}">...</td>

</tr>

<tr>

    <tdclass="{% cycle rowcolors %}">...</td>

    <tdclass="{{ rowcolors }}">...</td>

</tr>

对应的渲染的结果是:

<tr>

    <tdclass="row1">...</td>

    <tdclass="row1">...</td>

</tr>

<tr>

    <tdclass="row2">...</td>

    <tdclass="row2">...</td>

</tr>

但是一旦定义了cycle标签,默认就会使用循环中的第一个值。当你仅仅是想定义一个循环,而不想打印循环的值的时候(比如在父模板定义变量以方便继承),可以用cyclesilent参数(必须保证silentcycle的最后一个参数),并且silent也具有继承的特点。尽管上面第2行中的cycle没有silent参数,但是由于rowcoclors是前面定义的且包含silent参数的,所以第2cycle也具有silent 循环的特点。

{% cycle row1 row2 as rowcolors silent %}

{% cycle rowcolors %}

6debug:输出所有的调试信息,包括当前上下文和导入的模块。

7extends:表示当前模板继承了一个父模板,接受一个包含父模板名字的变量或者字符串常量。

8filter:通过可用的过滤器过滤内容,过滤器之间还可以相互(调用)。例如:

{% filter force_escape|lower %}

    Thistext will be HTML-escaped, and will appear in all lowercase.

{% endfilter %}

9firstof:返回列表中第一个可用(非False)的变量或者字符串,注意firstof中的变量不是自动转义的。例如:

{% firstof var1 var2 var3 "fallbackvalue" %}

10forfor循环,可以在后面加入reversed参数遍历逆序的列表。例如:

{% for obj in list reversed %

还可以根据列表的数据来写for语句,例如下面是对于字典类型数据的for循环。

{% for key, value in data.items %}

    {{ key}}: {{ value }}

{% endfor %}

另外,在for循环中还有一系列有用的变量,具体说明如下表2-1所示。

2-1  for循环中的变量

变量 

描述

forloop.counter

当前循环的索引,从1开始

forloop.counter0

当前循环的索引,从0开始

forloop.revcounter

当前循环的索引(从后面算起),从1开始

forloop.revcounter0

当前循环的索引(从后面算起),从0开始

forloop.first

如果这是第一次循环返回真

forloop.last

如果这是最后一次循环返回真

forloop.parentloop

如果是嵌套循环,指的是外一层循环

11for...empty:如果for循环只的参数列表为空,则执行empty里面的内容。例如:

<ul>

{% for athlete in athlete_list %}

   <li>{{ athlete.name }}</li>

{% empty %}

   <li>Sorry, no athlete in this list!</li>

{% endfor %}

<ul>

12if:这是一个条件语句,例如:

{% if athlete_list %}

    Numberof athletes: {{ athlete_list|length }}

{% elif athlete_in_locker_room_list %}

    Athletesshould be out of the locker room soon!

{% else %}

    No athletes.

{% endif %}

13)布尔操作符:在if标签只可以使用andornot三个布尔操作符,还有==!=<><=>=innot in等操作符。在if标签里面,通过这些操作符可以开发出复杂的表达式。

14ifchange:检测一个值在循环的最后有没有改变。这个标签是在循环里面使用的,有如下所示的两个用法:

  • 当没有接受参数时,比较的是ifchange标签里面的内容相比以前是否有变化,有变化时生效。

  • 当接受一个或一个以上的参数的时候,如果有一个或者以上的参数发生变化时,有变化时生效。

ifchange中可以有else标签,例如:

{% for match in matches %}

    <divstyle="background-color:

        {%ifchanged match.ballot_id %}

           {% cycle "red" "blue" %}

        {%else %}

           grey

        {%endifchanged %}

   ">{{ match }}</div>

{% endfor %}

14ifequal:仅当两个参数相等的时候输出块只的内容,可以配合else输出。例如:

{% ifequal user.username "adrian" %}

    ...

{% endifequal %}

15ifnotequal:功能和用法跟ifequal标签类似。

16include:用于加载一个模板并用当前上下文(include该模板的模板的上下文)渲染它,接受一个变量或者字符串参数,也可以在include的时候传递一些参数进来。例如:

{% include "name_snippet.html" withperson="Jane" greeting="Hello" %}

如果只想接受传递的参数,不接受当前模板的上下文时,可以使用only参数。例如:

{% include "name_snippet.html" withgreeting="Hi" only %}

17load:加载一个自定义的模板标签集合。

18now:显示当前的时间日期,接受格式化字符串的参数。例如:

It is {% now "jS F Y H:i" %}

在现实中已经定义好了一些格式化字符串参数,例如:

  • DATE_FORMAT(月日年)

  • DATETIME_FORMAT(月日年时)

  • SHORT_DATE_FORMAT(月//年)

  • SHORT_DATETIME_FORMAT(月///时)

19regroup:通过共同的属性对一个列表的相似对象重新分组,假如存在如下一个城市(city)的列表。

cities = [

    {name:Mumbai, population: 19,000,000, country: India},

    {name: Calcutta, population:15,000,000, country: India},

    {name:New York, population: 20,000,000, country: USA},

    {name:Chicago, population: 7,000,000, country: USA},

    {name:Tokyo, population: 33,000,000, country: Japan},

]

如果想按照国家country这个属性来重新分组,目的是得到下面的分组结果。

India

Mumbai: 19,000,000

Calcutta: 15,000,000

USA

New York: 20,000,000

Chicago: 7,000,000

Japan

Tokyo: 33,000,000

则可以通过如下代码实现上述要求的分组功能。

{% regroup cities by country as country_list %}

<ul>

{% for country in country_list %}

   <li>{{ country.grouper }}

   <ul>

        {%for item in country.list %}

         <li>{{ item.name }}: {{ item.population }}</li>

        {%endfor %}

   </ul>

   </li>

{% endfor %}

</ul>

值得注意的是,regroup并不会重新排序,所以必须确保cityregroup之前已经按country排好序,否则将得不到预期想要的结果。如果不确定cityregroup之前已经按country排好序,可以用dictsort进行过滤器排序。例如:

{% regroup cities|dictsort:"country" bycountry as country_list %}

20spaceless:移除html标签之间的空格,需要注意的是标签之间的空格,标签与内容之间的空格不会被删除。例如:

{% spaceless %}

   <p>

       <a href="foo/">Foo</a>

   </p>

{% endspaceless %}

运行结果是:

<p><ahref="foo/">Foo</a></p>

21ssi:在页面上输出给定文件的内容,例如:

{% ssi/home/html/ljworld.com/includes/right_generic.html %}

使用参数parsed可以使得输入的内容作为一个模板,从而可以使用当前模板的上下文。例如下面的演示代码:

{% ssi/home/html/ljworld.com/includes/right_generic.html parsed %}

22url:返回一个绝对路径的引用(没有域名的url),接受的第一个参数是一个视图函数的名字,然后从urls配置文件里面找到那个视图函数对应的url

23widthratio:计算给定值与最大值的比率,然后把这个比率与一个常数相乘,返回最终的结果。例如:

<img src="bar.gif"height="10" width="{% widthratio this_value max_value 100%}" />

24with 用更简单的变量名缓存复杂的变量名,例如:

{% with total=business.employees.count %}

    {{ total}} employee{{ total|pluralize }}

{% endwith %}

例如在下面的实例代码中,演示了在Django模板中使用for循环显示列表内容的过程。

源码路径:光盘:daima66-7iaoqian

1)通过如下命令分别创建一个名为“biaoqian”的项目和一个名称为“learn”的应用程序。

django-admin.py startproject biaoqian

cd biaoqian

python manage.py startapp learn

2)将上面创建的“learn”应用加入到 settings.INSTALLED_APPS中。

INSTALLED_APPS = (

   django.contrib.admin,

   django.contrib.auth,

   django.contrib.contenttypes,

   django.contrib.sessions,

   django.contrib.messages,

   django.contrib.staticfiles,

    learn,

)

3)为了将视图函数对应到网址,对文件urls.py的代码进行如下所示的修改。

from django.contrib import admin

from django.conf.urls import include, url

from learn import views as learn_views

urlpatterns = [

   url(r^$, learn_views.home, name=home),

   url(r^admin/, admin.site.urls),

]

4)在视图文件view.py中传递了一个List列表到模板 home.html,在列表中包含了5门编程语言的名字。文件view.py的具体代码如下所示。

from django.shortcuts import render

 

def home(request):

   TutorialList = ["Java", "C", "C++","Python", "C#"]

    returnrender(request, home.html, {TutorialList: TutorialList})

5)在模板文件home.html中使用for循环遍历列表中的内容,在for循环最后要有一个结束标记“endfor”。文件home.html的具体实现代码如下所示。

5大最流的编程语言列表:

{% for i in TutorialList %}

{{ i }}

{% endfor %}

6)输入如下命令启动服务器运行Web程序:

python manage.py runserver

执行后会在网页中显示在列表中存储的5门编程语言名字,执行效果如图6-1所示。

6-1  执行效果

6.7.4  模板继承

Django Web程序中,模板可以用继承的方式来实现复用,此功能需要使用extends标签实现。例如在下面演示模板继承代码中,模板文件template.html中的content模块会替换掉模板文件base.html中的content模块。同时模板文件template.html继承了模板文件base.htmlsidebarfooter模块。

# base.html

{% block sidebar %}

{% endblock %}

 

{% block content %}

{% endblock %}

 

{% block footer %}

{% endblock %}

 

# template.html

{% extends "base.html" %}

{% block content %}

        {{some code }}

例如在下面的实例代码中,演示了在Django模板中使用for循环显示列表内容的过程。

源码路径:光盘:daima66-7HelloWorld

1)通过如下命令分别创建一个名为“biaoqian”的项目和一个名称为“jicheng”的应用程序。

django-admin.py startproject HelloWorld

cd HelloWorld

python manage.py startapp jicheng

2)修改视图文件view.py,在里面增加一个新的对象,用于向模板中提交数据。

from django.shortcuts import render

 

from django.http import HttpResponse

 

def hello(request):

   context          = {}

   context[hello] = Hello World!

    returnrender(request, hello.html, context)

3)接下来需要向Django说明模板文件的路径,在前面我们使用的是将应用加入到 设置文件settings.pysettings.INSTALLED_APPS中,现在我们使用一种新的设置方法。打开设置文件settings.py,修改 TEMPLATES 中的 DIRS 为:[BASE_DIR+"/jicheng/templates",],具体代码如下所示。

TEMPLATES = [

    {

       BACKEND: django.template.backends.django.DjangoTemplates,

       DIRS: [BASE_DIR+"/jicheng/templates",],

       APP_DIRS: True,

       OPTIONS: {

           context_processors: [

               django.template.context_processors.debug,

               django.template.context_processors.request,

               django.contrib.auth.context_processors.auth,

               django.contrib.messages.context_processors.messages,

           ],

        },

4)在子目录“jicheng”下面创建目录“templates”,然后在里面创建模板文件base.htmlhello.html。其中文件base.html的具体实现代码如下所示。

<html>

 <head>

   <title>Hello World!</title>

 </head>

 

 <body>

   <h1>Hello World!</h1>

    {% blockmainbody %}

      <p>original</p>

    {%endblock %}

 </body>

</html>

在上述代码中,名字为mainbodyblock标签可以被继承者们替换掉。通过所有的{% block %} 标签告诉模板引擎,子模板可以重载这些部分。

模板文件hello.html继承base.html,并替换特定的block,文件hello.html的具体实现代码如下所示。

{% extends "base.html" %}

 

{% block mainbody %}

<p>继承了 base.html 文件</p>

{% endblock %}

在上述代码中,第一行代码说明模板文件hello.html继承自文件base.html。使用相同名字的block标签可以替换文件base.html中相应的block

5)输入如下命令启动服务器运行Web程序:

python manage.py runserver

执行后效果如图6-1所示。



6-1  执行效果


Python三叔(欢迎入QQ群:292693408)


    发送中

    上一篇:html5点击按钮酷炫云雾动画弹出文字..

    下一篇:没有了

    相关文档推荐

    精品模板推荐

    专业的织梦模板定制下载站,在线购买后即可下载!

    商业源码

    跟版网模板,累计帮助5000+客户企业成功建站,为草根创业提供助力!

    立刻开启你的建站之旅
    
    QQ在线客服

    服务热线

    织梦建站咨询