一.模板路径的查找
1-查找顺序
(1)首先查找模板设置路径:项目文件夹,settings.py中的TEMPLATES里面的DIRS,DIRS的值是个列表,里边可以存放多个路径,django项目会在这个列表里自动从前往后找】
(2)接着去看APP_DIRS里,判断它的值,如果这个值为True(默认为True),则django会到同样是项目文件夹中的settings.py中的INSTALLED_APPS(注册了的app)中,依次去找,这也是个列表,查找顺序从上到下
所以也可以在app目录下存放模板:例如最上面加一行'teacher.apps.TeacherConfig'来注册这个app,或者可以直接简写为‘teacher’
这样django会去teacher这个app的文件夹中,去寻找有没有templates(模板),这样在app中如果有templates文件夹,也可以找到了,
注意app中的模板文件夹必须叫templates,不然找不到;项目根目录中的模板文件夹可以随便起名
在相应app的视图函数中,return render(request,‘html2.html’)直接写html文件名称就可以,不需要路径了。
settings中
INSTALLED_APPS = [ 'students.apps.StudentsConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
视图函数中
def index(request): return render(request, 'html_student_index.html')
2-两种方案 优先级,DIRS里的路径优先级高于INSTALLED_APPS,一种是集中存放一种是分散在app中
(1)集中存放,方便管理,方便继承,一般做大项目,需要集中管理,部署,会把模板集中存放
(2)分散在app中,是app可以复用的时候,复用,一个app可以被用于多个项目
3-为什么要在集中存放的tempaltes里面再套一层
** 只要找到一个符合的模板,就返回,
1)不同app如果有同名的模板,前面的会覆盖后面的,所以要把每个app的模板分开放,这样文件名加上相对路径,就不会重复了,也便于管理后期查找
2)因为集中存放的优先级高,不加一层目录的话,渲染模板也是render(request,‘html2.html’),和app里存放的模板调用的时候同名,
同名的情况下,集中存放的优先级高,匹配到集中存放的,就不会再去app中的模板文件夹去找了,
所以集中存放要给每个app再加一层文件夹,区分一下相对路径和名字,避免想调用app里模板文件调用不到的情况
二.模板变量
1)首先要明白什么是静态页面什么是动态页面
(1)静态页面,即静态网页,是实际存在的,无需经过服务器的编译,直接加载到客户浏览器上显示出来,只加载一次。静态页面需要占一定的服务器空间,且不能自主管理发布更新的页面,
如果想更新网页内容,要通过FTP软件把文件DOWN下来用网页制作软件修改(通过fso等技术例外)。常见的静态页面举例:.html扩展名的、.htm扩展名的。
静态网页每个网页都有一个固定的URL
(2)动态页面,只要是采用了动态网站技术生成的网页都可以称为动态网页。页面代码虽然没有变,但是显示的内容却是可以随着时间、环境或者数据库操作的结果而发生改变的。
动态网页是基本的html语法规范与Java、VB、VC等高级程序设计语言、数据库编程等多种技术的融合,以期实现对网站内容和风格的高效、动态和交互式的管理。
因此,从这个意义上来讲,凡是结合了HTML以外的高级程序设计语言和数据库技术进行的网页编程技术生成的网页都是动态网页。
以.aspx、.asp、.jsp、.php、.perl、.cgi等形式为后缀,并且在动态网页网址中有一个标志性的符号——“?”。
(3)静态:优点,速度快,可以跨平台,跨服务器,安全。
缺点,更新困难,无法实现一些WEB应用。最明显的一点搜索。
动态:优点,可用于在服务器上生成功能强大的 Web应用程序,增强的性能,世界级的工具支持,威力和灵活性。
缺点,速度不占优势,在搜索引擎收录方面不占优势,动态网页是在用户输入指令后才形成的页面,并不存在这个页面,而搜索引擎只会抓取现成的,并不会自己输入
2)渲染 render方法会动态的生成最终的返回结果,例如在页面上显示当前服务器时间,可以定义一个变量,按照一定的语法把变量的值渲染到模板中,本质:在最底层是字符串格式化
(1)需要加动态效果的视图函数中定义变量,在返回的render方法中,模板参数后加个context参数,他是个字典,键是自己起名,值是上面定义的变量
(2)在对应的模板文件中,使用这个变量,要用双层的花括号扩起来{{变量名}},注意模板里的变量名必须和视图函数中return出去的context里面的key对应,而不是和视图函数中定义的变量名对应
(3)视图函数中返回的render方法会帮我们把这个变量值替换到模板中的这个指定位置
如果变量是时间,不同时间访问它,页面显示就不同,课堂上简单例子是UTC时间,
def index(request): now = datetime.now()#拿到当前时间,把他传给模板
return render(request, 'app1/html1.html', context={ 'now': now, )
<h2>当前时间是:{{now}}</h2>
想设置不是UTC时间,可以更改项目文件夹settings.py中的TIME_ZONE的值,改为你想显示的时区的时区简写,比如'Asia/Shanghai'
# Internationalization # https://docs.djangoproject.com/en/2.1/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = True
3)模板变量
命名:和python中变量命名规则差不多,由字母、数字、下划线组成, 不能以下划线开头,不能有空格和下划线以外的标点符号,不能用python和django的关键字命名
变量的值:可以是python中的任意数据类型,包括函数,方法,属性,对象实例等等,是对象实例的时候,页面上解析出的是他的print值渲染上去的
4)变量的解析规则
1***举例一:(1)渲染列表:1.视图函数中定义变量,列表类型比如lt = [1,2,3],return中加上context={'lt':lt}
2.模板文件中<p>我是个列表:{{lt}}</p>
结果,显示整个列表
(2)渲染列表中某个值:
1.视图函数中还是用原来的参数
2.模板的变量名后加.索引值(索引值对应列表,取第二个值,索引是1,以此类推,模板文件中<p>我是列表中第二个值:{{lt.1}}</p>
(3)渲染函数:1.视图函数中定义函数,在视图函数本身的return中的context参数中加上key:里层函数名,里层函数名不要带上括号
2.模板中加上{{key}},这里的key和上面那些一样,还是和之前一样,是视图函数中的对应参数的key,注意key还是不要加()
3.如果里层函数有返回值,则页面中指定位置显示里层函数返回值,没有返回值,则网页对应位置显示None
(4)渲染字典: 1.视图函数中定义字典,返回的context参数中加上key:字典名
2.模板中加上{{key}}
3.结果是页面中显示整个字典
(5)渲染字典中某键的值 1.视图函数还是用上面的参数
2.模板中{{key.字典里想取的值的key}}
3.结果显示字典里的对应值
(6)渲染对象的某个方法:1.视图函数里还是用上面的字典不变
2.模板中{{key.该变量的方法}} ,比如<p>我调用字典的方法items:{{dc.items}}</p>
3.显示该变量使用某方法后的返回值:
dict_items([('day4', '魔王抛弃了大白兔,选择留下勇者啦'), ('day1', '大白兔被魔王抓走啦'), ('day2', '大白兔被魔王那啥啦'), ('day3', '勇者来救大白兔啦')])
4.视图函数中定义的变量,如果该变量的对象本身有叫做那个方法的键:比如dt = {'name':"心蓝",‘age':18,'items':'adc'},然后把'dt':dt放进context参数中return出去
5.模板中{{key.该变量被定义了同名的键的方法},具体例子是{{dt.items}}
6.结果显示字典中写好的值,而不是该对象的方法值(因为变量解析先进行字典键值查找,再进行方法属性查找)
def index(request): now = datetime.now()#拿到当前时间,把他传给模板 lt = [1, 2, 3] def func(): t = 1+1 # return '我是一个函数,你是谁鸭' dc = {"day1": "大白兔被魔王抓走啦", 'day2': "大白兔被魔王那啥啦", "day3": "勇者来救大白兔啦", "day4": "魔王抛弃了大白兔,选择留下勇者啦" } dt = {'name': "心蓝", 'age': 18, 'items': 'adc' } return render(request, 'app1/html1.html', context={ 'now': now, 'lt': lt, 'funccc': func, 'dc': dc, 'dt': dt, })#加一个context参数,他是个dict,带上这个参数,在模板里可以使用他
<body> <h1>我是app1中的主页面</h1> <h2>当前时间是:{{now}}</h2> <p>我是个列表:{{lt}}</p> <p>我是列表中第二个值:{{lt.1}}</p> <p>我是个函数:{{funccc}}</p> <p>我是个字典:{{dc}}</p> <p>我是字典里的一个值:{{dc.day2}}</p> <p>我调用字典的方法items:{{dc.items}}</p> <p>我调用字典的方法items:{{dt.items}}</p> <form action=""> <p>用户名: <input type="text"></p> <p>密码: <input type="password"></p> <p><input type="submit" value="登陆"></p> </form> </body>
2.***具体的解析规则
1).计算变量,将其替换为结果(变量是个表达式的话,页面上会显示表达式计算后的结果)
2).遇到点(.)的时候,按一下顺序查找:
-1.字典键值查找
-2.属性或方法查找
-3.数字索引查找
3.***如果结果是可调用的,则调用它时不带参数,调用的结果成为模板的值。见上面的示例3
如果给里层函数传进去参数,则渲染失败
比如示例3中的视图函数定义时给里层函数加上参数(aaa),这个函数就不会被渲染了
## 所谓的结果是可调用的,说明变量是个函数,或是个方法
4.** 渲染失败返回'',空字符串