好记性不如铅笔头

Django, web, 编程

Django自学笔记:模板

最近自学了下Django,这里笔记下学习记录。

备注:

1 学习记录中的代码和资料参考自网络教程【 http://djangobook.py3k.cn/2.0/ 】和【 http://www.djangobook.com/en/2.0/ 】,版权归原作者所有。
2 小弟第一次接触到Django,本笔记可能有错误,还请各位路过的大牛们给予指点。
3 由于教程年代比较久远了,而且Django不同版本改动很大,这里作者的学习笔记是基于【 python2.7.8 + django1.6.5 】实现的。
4 由于时间关系,学习记录里有的地方记得比较乱,以后有时间再整理下吧。

添加模板:

支持模板原理代码:

首先看下Django是如何支持模板的,开启一个新的CMD,然后输入如下命令:

D:\Documents\pythons\HelloDjango>python manage.py shell
Python 2.7.8 (default, Jun 30 2014, 16:08:48) [MSC v.1500 64 bit (AMD64)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context({'name': 'Adrian'})
>>> print t.render(c)
My name is Adrian.
>>> c = template.Context({'name': 'Fred'})
>>> print t.render(c)
My name is Fred.
>>> c = template.Context()
>>> print t.render(c)
My name is .

因此可知:
在Python代码中使用Django模板的最基本方式如下:
1. 创建一个 Template 对象,将模板代码放入一个 string 中作为参数。
2. 调用模板(template)对象的 render() 方法,把一组变量作为上下文(context)传入。这么做将会把模板(template)展开,将所有变量(variables)和标签(tags)都赋予相应的值,并作为 string 返回。

Django加载模板文件:

由于Django版本间有差异,这里作者使用的是1.6.5版本,这里作者笔记下如何加载模板文件:
首先在HelloDjango 文件夹下新建一个文件夹【 templates 】,目录结构为:
D:\Documents\pythons\HelloDjango\HelloDjango\templates
然后在templates文件夹下新建一个文件【 HelloTemplates.html 】,内容很简单,Hello Templates,如下图:

然后添加URL解析代码,如下图: 

之后有很重要的一个步骤,打开settings.py,在INSTALLED_APPS中加入一行,如下图:

然后刷新下网页,就可以了:

这里笔记下为什么这样放置template:

在看教程时,发现很多人在settings.py里面添加变量TEMPLATE_DIRS来实现tempate的查找,这里我们看下网址【  https://docs.djangoproject.com/en/1.6/ref/settings/#std:setting-TEMPLATE_DIRS 】中,

TEMPLATE_DIRS
Default: () (Empty tuple)
List of locations of the template source files searched by django.template.loaders.filesystem.Loader, in search order.
Note that these paths should use Unix-style forward slashes, even on Windows.
See The Django template language.

即该变量表示了如何要查找template的目录,这里我们继续看网址【 https://docs.djangoproject.com/en/1.6/ref/templates/api/#django.template.loaders.filesystem.Loader 】,

class app_directories.Loader
Loads templates from Django apps on the filesystem. For each app in INSTALLED_APPS, the loader looks for a templatessubdirectory. If the directory exists, Django looks for templates in there.
This means you can store templates with your individual apps. This also makes it easy to distribute Django apps with default templates.
For example, for this setting:
INSTALLED_APPS = ('myproject.polls', 'myproject.music')

...then get_template('foo.html') will look for foo.html in these directories, in this order:
?/path/to/myproject/polls/templates/
?/path/to/myproject/music/templates/
... and will use the one it finds first.

因此可以通过在INSTALLED_APPS中注册新的APP的方法来实现查找,不过这里需要把template文件放到templates文件夹中,这里我们为了简单,就采取这种方式。

模板语法:

.运算符:

通过.运算符可以方便的调用到字典变量:

>>> t = template.Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = template.Context({'person':  {'name': 'Sally', 'age': '43'}})
>>> t.render(c)
u'Sally is 43 years old.'
>>>

也可以访问类的成员变量:

>>> class Person(object):
...     def __init__(self, first_name, last_name):
...             self.first_name, self.last_name = first_name, last_name;
...
>>> t = template.Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = template.Context({'person': Person('John', 'Smith')})
>>> t.render(c)
u'Hello, John Smith.'
>>>

也可以调用到无参数的方法:

>>> t = template.Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(template.Context({'var': 'hello'}))
u'hello -- HELLO -- False'
>>> t.render(template.Context({'var': '123'}))
u'123 -- 123 -- True'
>>>

也可用于访问列表索引:

>>> t = template.Template('Item 2 is {{ items.2 }}.')
>>> c = template.Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
u'Item 2 is carrots.'
>>>

句点查找规则可概括为:当模板系统在变量名中遇到点时,按照以下顺序尝试进行查找:

1 字典类型查找 (比如 foo["bar"] )
2 属性查找 (比如 foo.bar )
3 方法调用 (比如 foo.bar() )
4 列表类型索引查找 (比如 foo[bar] )

if else:

HelloTemplates.html:

{% if today_is_weekend %}
    <p>Welcome to the weekend!</p>
{% else %}
    <p>Get back to work.</p>
{% endif %}

MyViewControllers.py:

def showtemplates(request):
    t = template.loader.get_template('HelloTemplates.html');
    c = template.Context();
    
    c['today_is_weekend'] = True;
    
    html = t.render(c);
    return HttpResponse(html);

and or not:

HelloTemplates.html:

<p>num1:{{num1}};num2:{{num2}};num3:{{num3}};num4:{{num4}};</p>

{% if num1 == 1 or num2 == 2 %}
		<p>num1 = 1 or num2 = 2</p>
{% endif %}

{% if num1 == 1 and num3 == 3 %}
		<p>num1 = 1 and num3 = 3</p>
{% endif %}

{% if not num4 == 4 %}
		<p>num4 != 4</p>
{% endif %}

MyViewControllers.py:

def showtemplates(request):
    t = template.loader.get_template('HelloTemplates.html');
    c = template.Context();
    
    c['num1'] = 1;
    c['num2'] = 2;
    c['num3'] = 3;
    c['num4'] = 5;

    html = t.render(c);
    return HttpResponse(html);

输出:

for:

reversed:使得该列表被反向迭代。
在执行循环之前先检测列表的大小是一个通常的做法,当列表为空时输出一些特别的提示。

HelloTemplates.html:

{% for athlete in athlete_list %}
	{{ athlete.name }}<br/>
{% empty %}
	There are no athletes. Only computer programmers.<br/>
{% endfor %}
 <p>==</p>
{% for athlete in athlete_list reversed %}
	{{ athlete.name }}<br/>
{% endfor %}

MyViewControllers.py:

def showtemplates(request):
    t = template.loader.get_template('HelloTemplates.html');
    c = template.Context();
    
    c['athlete_list'] = [{'name':'xiaoming'},{'name':'xiaoqiang'},{'name':'xiaoli'}];
    
    html = t.render(c);
return HttpResponse(html);

输出:

forloop:

HelloTemplates.html:

{% for athlete in athlete_list %}
	<p>{{ athlete.name }}</p>
	forloop.first:{{forloop.first}} <br/>
	forloop.last :{{forloop.last }} <br/>
	forloop.counter:{{forloop.counter}} <br/>
	forloop.counter0 :{{forloop.counter0 }} <br/>	
	forloop.revcounter  :{{forloop.revcounter  }} <br/>	
	forloop.revcounter0  :{{forloop.revcounter0  }} <br/>	
{% endfor %}

MyViewControllers.py:

def showtemplates(request):
    t = template.loader.get_template('HelloTemplates.html');
    c = template.Context();
    
    c['athlete_list'] = [{'name':'xiaoming'},{'name':'xiaoqiang'},{'name':'xiaoli'}];
    
    html = t.render(c);
return HttpResponse(html);

输出:

多层循环:

HelloTemplates.html:

{% for country in countries %}
    <table>
    {% for city in country.city_list %}
        <tr>
        <td>Country #{{ forloop.parentloop.counter }}</td>
        <td>City #{{ forloop.counter }}</td>
        <td>{{ city }}</td>
        </tr>
    {% endfor %}
    </table>
{% endfor %}

MyViewControllers.py:

def showtemplates(request):
    t = template.loader.get_template('HelloTemplates.html');
    c = template.Context();
    
    c['countries'] = [{'city_list':['beijing','shanghai','nanjing']},{'city_list':['New York','LA']}];
    
    html = t.render(c);
return HttpResponse(html);

输出:

注释:

{# This is a comment #}

{% comment %}
This is a
multi-line comment.
{% endcomment %}

简化后的模板加载代码:

HelloTemplates.html:

Hello My Blog Is {{myblog}}.

MyViewControllers.py:

from django.shortcuts import render;
def showtemplates(request):
    return render(request, 'HelloTemplates.html', {'myblog':'http://116.62.110.235/blog/'})

Include标签:

首先新建一个文件夹navs,在里面新建一个html文件:HelloNav.html,内容为:

<p>YOU ARE IN {{navtitle}}</p>

如下图:

HelloTemplates.html:

{% include "navs/HelloNav.html" %}
<p>
The Content IS:<br/>
{{content}}
</p>

MyViewControllers.py:

def showtemplates(request):
    t = template.loader.get_template('HelloTemplates.html');
    c = template.Context();
    c['navtitle'] = 'Hello This Is Title';
    c['content'] = 'Hello This Is Content';
   
    html = t.render(c);
    return HttpResponse(html);

输出:

模板:

{% block %}

{% block %} 标签告诉模板引擎,子模板可以重载这些部分。 每个{% block %}标签所要做的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。

首先新建一个父模板文件base.html,内容如下:

{{ title }}
<h1>This Is Content A</h1>
{% block contentA %}
<p>Hello This Is The ContentA In base.html.</p>
{% endblock %}
<h1>This Is Content B</h1>
{% block contentB %}
<p>Hello This Is The ContentB In base.html.</p>
{% endblock %}
<h1>This Is Content C</h1>
{% block contentC %}{% endblock %}

然后我们修改HelloTemplates.html,让其继承自base.html:

{% extends "base.html" %}

{% block contentA %}
This Is The ContentA In HelloTemplates.html
{% endblock %}

{% block contentC %}
{{content}}
{% endblock %}

{% block contentD %}
This Is The ContentD In HelloTemplates.html
{% endblock %}

MyViewControllers.py:

def showtemplates(request):
    t = template.loader.get_template('HelloTemplates.html');
    c = template.Context();
    c['title'] = 'Hello This Is Title';
    c['content'] = 'Hello This Is Content';
   
    html = t.render(c);
    return HttpResponse(html);

如下图: 

各个block之间的关系:

{{block.super}}:

base.html:

{{ title }}
<h1>This Is Content A</h1>
{% block contentA %}
<p>Hello This Is The ContentA In base.html.</p>
{% endblock %}

HelloTemplates.html:

{% extends "base.html" %}

{% block contentA %}
 {{ block.super }}
This Is The ContentA In HelloTemplates.html
{% endblock %}

输出:

备注:

一些有意思的评注:

Leave a Reply

19 + 17 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据