Django:模板系统_基础

模板

1、在前面的章节例子中我们都是使用:django.http.HttpResponse来把指定的字符串内容显示到网页上。而实际生活中其实很少这样用,因为实际中的页面都是带有样式的HTML代码,这样就可以让浏览器渲染出非常漂亮的页面

2、目前市面上有非常多的模板系统,其中最知名最好用的就是DTL和Jinja2。DTL是Django Template Language三个单词的缩写,也就是Django自带的模板语言。当然也可以配置Django支持Jinja2等其他模板引擎,但是作为Django内置的模板语言,DTL和Django可以达到无缝衔接而不会产生不兼容的情况。因此下面我们都是采用的DTL

 

 

模板和普通HTML文件的区别

DTL模板是一种带有特殊语法的HTML文件,这个HTML文件可以被Django编译,可以传递参数进去,实现数据动态化。在编译完成后,生成一个普通的HTML文件,然后发送给客户端

注:
一般的HTML文件中就只有HTTML标签对等,但DTL模板中不仅有HTML标签对,还可以有if判断、for循环等(感觉就是一些逻辑可以在HTML代码中进行,而不需要在后台代码中进行)

 

 

渲染模板

渲染模板有很多种方式,这里介绍下两种常用的方式

render_to_string()

找到对应的模板,然后将模板编译后渲染成Python的字符串格式。最后在通过HttpResponse类包装成一个HttpResponse对象返回回去

例1:

⑴编辑视图
Django:模板系统_基础


⑵编辑模板(HTML)

Django:模板系统_基础


⑶编辑URL

Django:模板系统_基础


⑷访问

Django:模板系统_基础

注:上面例子中
1、"index.html"文件是放在根目录下的Templates文件夹中的。这个文件夹是我们在使用Pycharm创建工程时自动生成的。如果每个APP的HTML代码都放在这个文件夹里面的话,就会显得很混乱,所以我们可以在每个app下面在新建一个Templates文件夹用来存放该APP中的HTML文件,只是说在APP下新建Templates文件夹需要单独设置一下。这个后面介绍

2、在编辑视图函数的时候,在代码中我们是直接传入的HTML文件的名字"html = render_to_string("index.html")",而没有告诉Django这个HTML文件的路径等,但是最后Django还是自动找到了这个文件,这里面就说明了,Django在查找HTML文件时是有一定的逻辑的,具体的逻辑,后面介绍

3、上面例子中流程大概是:使用render_to_string()函数将一个HTML模板渲染成一个字符串,然后再使用HttpResponse()函数,将这个字符串返回。这里面需要注意的就是,不能直接HttpResponse("index.html"),这样的话,就只会返回"index.html"这个字符串

 

render()

上面例子中渲染模板的方式虽然已经很方便了,但是Django还提供了一个更加简便的方式:直接将模板渲染成字符串和包装成HttpResponse对象,一步到位

例2:

⑴编辑视图

Django:模板系统_基础


⑵访问

Django:模板系统_基础


⑶查看render()函数源码

Django:模板系统_基础

注:
1、例1与例2的区别只是在于视图函数中分别使用了render_to_string()方法和render()方法,可以看出:render()函数比render_to_string()函数更加简便,render()函数使用一行代码就可以完成的,render_to_string()函数需要两行

2、从render()方法的源码中也可以看出来:render()方法其实是将render_to_string()和HttpResponse()封装进去了。所以render()方法更加简便。后面直接使用render()方法就可以了

3、只是说在使用render()方法时,render()方法的第一个参数必须是request,后面才是HTML模板名

4、Django中还有一个方法叫render_to_response(),这个方法与render()方法一模一样,只是说render_to_response()方法马上就会被弃用了

 

 

模板查找路径配置

上面例子中我们在视图函数中,只是传进了HTML模板的名字,而没有告诉Django,模板的具体路径,但是最后Django还是自动寻找到了模板。这个是为什么呢?Django之所以会自动且正确的查找到对应的模板文件,是因为,在项目的settings.py文件中,有一个TEMPLATES的配置,这个配置包含了模板引擎的配置,模板查询路径的配置,模板上下文的配置等。模板路径可以在两个地方配置
    1、'DIRS':这是一个列表,在这个列表中可以存放所有的模板路径。以后在视图中使用render()或者render_to_string()渲染模板的时候,就会在这个列表的路径中查找模板。即Django会默认的在这个列表中配置的路径下去寻找模板

    2、'APP_DIRS':默认值为True,这个设置为True后,会在INSTALLED_APPS配置中的所有的app下的Templates文件夹中查找模板。(这就是前面例子以及第一篇文章中说的:为什么在创建一个app后,需要在INSTALLED_APPS中注册这个app的原因了,为了后面能在该app下的Templates文件夹中查找模板)

Django:模板系统_基础

 

DIRS

1、'DIRS'中的BASE_DIR代表的是当前项目的路径,如果我们对其进行打印的话,就会看到输出的是F:\Pycharm_project\Web。即当前项目的路径

2、BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    ⑴从上面代码中可以看出,这个BASE_DIR的值其实是一个动态的值,也就是其是根据项目实际所在路径来确定的(Python中的OS模块)

3、'DIRS'列表中的os.path.join(BASE_DIR, 'templates')表示:将BASE_DIR的值与'templates'拼接成一个路径,也就是我们根模板templates的路径。所以前面的例子中Django就会在这个拼接出来的路径下去找对应名字的模板HTML文件了
    ⑴在我自己这个项目中os.path.join(BASE_DIR, 'templates')其实就等于r"F:\Pycharm_project\Web\templates",只是说os.path.join(BASE_DIR, 'templates')这样写的话,路径是一个动态的值,可以根据项目实际位置来确定其路径,如果写死了路劲的话,就只能在这个写死的路径下查找了
    ⑵当然我们也可以将DIRS'的值配置成我们自己某个文件夹的路径,只是说不建议这么做,还是保持默认设置比较好

 

APP_DIRS

在Django的默认设置中'APP_DIRS'的值是True。这个表示,Django不仅会在BASE_DIR中的路径下去寻找模板,还是在每个注册了的APP下去寻找模板(如果这个值为False的话,就表示不会去app下寻找了)

例3:

⑴编辑视图

Django:模板系统_基础


⑵编辑模板HTML
    ①在应用程序app下新建一个存放模板的文件夹
    ②再在新建的模板文件夹下编写模板
    ③模板文件夹的名字必须要是templates,不能是其他的,如果是其他名字的话,Django也不能找到

Django:模板系统_基础


⑶访问

Django:模板系统_基础


⑷注册app
    ①这个例子中Django之所以能正确找到对应的模板文件,有两点需要注意:一是我们在settings.py文件中的"INSTALLED_APPS"中注册了这个app,而是因为"TEMPLATES "中'APP_DIRS'的值是True
    ②从这个例子中可以看出:我们在新建一个应用程序app后一定要注册(安装)这个app,不然后面在在这个app下寻找模板时,可能会出现找不到的情况。还有就是'APP_DIRS'的值一定要是True
    ③注册应用程序app的方法是:将应用程序app的名字加到INSTALLED_APPS列表中(如果app不进行注册,只是'APP_DIRS'=True的话,Django是不能找到APP下的模板的,所以一定要注册app)

Django:模板系统_基础

 

 

 

模板查找顺序

比如模板代码render("list.html")。在查找其模板时,会按照以下顺序来进行查找:

1、先在DIRS这个列表中依次查找每个路径下有没有对应的模板(名为list.html),如果有就返回,如果没有的话,进行下一步
    ⑴DIRS是一个列表,其里面可能会存放多个路径,因此在查找模板时,会依次在每个路径下进行查找

2、如果在DIRS中所有路径下都没有找到对应的模板的话,那么就会先检查当前这个视图所处的app是否已安装(注册),如果已经安装了,那么就先在当前这个app下的templates文件夹中查找模板
    ⑴如果当前app没有安装,那么就直接去其他已经安装了的app下寻找

3、如果在当前app下没有找到模板的话,那么就会在其他已经安装了的app中查找

4、如果在所有路径下都没有找到对应模板的话,就会抛出一个TemplateDoesNotExist的异常

 

 

 

模板语法:变量

1、前面我们学习的页面都是固定的,即,前端页面显示什么,是在后台写死了的,不能随意改变。但是实际中大部分页面都是动态的,页面显示的内容是可以变化的。如,我们在页面上会看到,谁登录的就会显示谁的信息,这种效果其实就是使用变量来实现的

2、模板中可以包含变量,Django在渲染模板的时候,可以传递变量对应的值过去进行替换

3、Django中变量的命名规范和Python非常类似,只能是以阿拉伯数字、英文以及下划线的组合,不能出现标点符号等特殊字符

4、变量需要通过视图函数渲染,视图函数在使用render()或者render_to_string()函数的时候可以传递一个context的参数,这个参数是一个字典类型。后面在模板中的变量就是从这个字典中读取值的

5、下图为render()函数的源代码:
    ⑴其中context参数中文意思为"上下文"。这个context参数就是用来专门存储这些需要传递的参数的
    ⑵context参数必须为字典类型。因此在模板中访问这些变量的时候,就会去这个context字典中根据键名来获得对应的值
    
Django:模板系统_基础


例4:普通字典
⑴编辑视图
    在视图函数中定义一个字典型的变量,并将其赋值给render()函数中的默认参数context

Django:模板系统_基础

⑵编辑模板
    上面步骤中,我们在视图函数中传递了一个名为"roleInfo"的变量,因此就需要在对应的模板中进行接收这个变量。如果模板中没有进行接收的话,这个变量就不会进行显示了

Django:模板系统_基础

注:
1、上面例子中,双大括号"{{键名}}"是Django模板语言中的属性访问语法

2、模板中的变量同样也支持英文点符号"."的方式来访问属性。比如person.username(这种方式只适用于字典值为类对象或者嵌套字典)。其中person是视图通过字典形式传递给模板的变量,然后通过"."点方式来访问username的属性
    ⑴不管person是否是一个字典还是一个类(对象),都不能使用{{字典名.键名}}来获取对应的属性。使用这种方式的话,是不能获取到对应变量值的。访问字典属性的话,只能通过{{键名}}来获取

3、模板在进行变量解析的时候会按照以下方式来进行解析:
    ⑴如果person是一个字典,那么就会查找这个字典的username这个key对应的值。即通过{{键名}}
    ⑵如果person是一个(类)对象,那么就会查找这个对象的username属性,或者是username这个方法(字典也是一个对象,在python中万物皆对象)。即通过{{键名.属性名}}
    ⑶如果出现的是person.1,则会判断person是否是一个列表或者元组或者任意可以通过下标来访问的对象,如果是的话就取这个列表的第一个值,如果不是就获取到的是一个空字符串


例4_1:键的值为一个类对象(属性)

⑴编辑视图

Django:模板系统_基础


⑵编辑模板

Django:模板系统_基础


⑶访问

Django:模板系统_基础

注:从上面例子的输出可以看出

1、如果字典中键的值是一个类对象的话,就需要使用:{{键名.属性名}}的方式来访问了
    ⑴不能直接使用{{属性名}}来访问,这种方式是获取不到的,因为这样会将属性名判断成键名,但是字典中又没有这个键,因此就获取不到了
    ⑵同样值为一个类对象时,也不能使用{{键名}}来访问,这样返回的就是这个类对象所在的内存地址了,如<polls.views.Person object at 0x000001D52683D588>

2、如果字典中键的值不是一个类对象(就是一个普通的对象:数字、字符串等)。就可以直接使用:{{键名}}来访问值了

3、不管字典中键的值是不是一个普通对象还是一个类对象,都不能使用{{字典名.键名}}的方式来访问。访问属性的方式中只能以键名开始


例4_2:值为类对象(方法)

⑴编辑视图
Django:模板系统_基础


⑵编辑模板
Django:模板系统_基础


⑶访问
Django:模板系统_基础

注:可以看出
字典的值为一个类对象时,不管访问的是实例属性、类属性、方法,都可以通过:{{键名.属性名}}、{{键名.方法名}}来访问值

 

例4_3:键的值为一个字典

⑴编辑视图
Django:模板系统_基础

⑵编辑模板
Django:模板系统_基础

⑶访问
Django:模板系统_基础

注:
Django获取变量值时,不能通过中括号的形式来获取字典和列表中的值,比如dict['key']和list[1],这种方式在模板语法中是不支持的
    ⑴比如最前面例子中获取字典中键的值时,不能通过:字典名['key']来获取
    ⑵又比如上个例子中,在获取内层字典的值时不能通过:people['username']来获取。
    ⑶Django模板语法中获取字典中键的值的方式是跟Python语法不一样的。一定需要注意
    
    
例4_4:键的值为列表

⑴编辑视图
Django:模板系统_基础

⑵编辑模板
Django:模板系统_基础

⑶访问
Django:模板系统_基础

注:从上面的例子中可以看出
1、模板语法中:如果字典中键的值为一个列表的话,可以使用{{键名.索引数}}的方式来获取列表中对应的值

2、在模板语法中,索引数也是不能超过列表的最大索引数的,虽然不会报错,但是获取的值为空

3、模板语法中获取列表中的值与Python语法中获取列表中的值又不一样了。python语法中获取列表中的值是list[索引数]

 

例5:python字典方法来作为字典的键

⑴编辑视图
Django:模板系统_基础

⑵编辑模板
    如果字典中键的值为嵌套字典的话,就可以使用字典方法了,如keys()、values()、items()等了
Django:模板系统_基础

⑶访问
    可以看出这里的输出与Python语法中的输出是一样的
Django:模板系统_基础

 

例5_1:python字典方法来作为字典的键(冲突)

⑴编辑视图
    使用Python中字典方法名来作为字典的键名
Django:模板系统_基础


⑵编辑模板
Django:模板系统_基础

⑶访问
Django:模板系统_基础

注:
从例5和例5_1两个例子的输出结果差异可以看出:在定义字典的键名时,不要使用字典方法名来作为字典的键名,不然会产生冲突。如keys、values、items等

 

 

拓展:网页中的动态页面和静态页面

静态页面

1、静态页面是网页的源代码都在页面中,不需要执行asp,php,jsp,.net等程序生成客户端网页代码的网页。(不随时间的变化而发生相应的网页内容的变化叫静态页面)

2、常见的静态页面举例:.html扩展名的、.htm扩展名的。

3、注意:静态页面并非网站上没有动画的就是静态页面。


动态页面

1、动态页面是通过执行asp,php,jsp,.net等程序生成客户端网页代码的网页。动态页面通常可以通过网站后台管理系统对网站的内容进行更新管理。发布新闻,发布公司产品,交流互动,博客,网上调查等,这都是动态网站的一些功能。也是我们常见的。(随时间的变化而发生相应的网页内容的变化叫做动态页面)

2、动态页面常见的扩展名有:.asp .php .jsp .cgi 等。

3、注意:动态页面的“动态”是网站与客户端用户互动的意思,而非网页上有动画的就是动态页面。