Python——Django框架(二)
参考博文:https://www.cnblogs.com/yuanchenqi/articles/6083427.html
一、视图函数介绍
path: 请求页面的全路径,不包括域名
get_full_path(): 比如:http://127.0.0.1:8000/index33/?name=123 ,
req.get_full_path()得到的结果就是/index33/?name=123
local(): 把局部变量渲染到模板里
如果这里有个request,页面一样可以渲染,因为这也是局部变量。但是不建议这么做,听说这会把所有的局部变量都取过来。
render_to_response:3.0版本中移除了render_to_response,只能用render。
1、render、redirect——跳转页面的不同
可以跳转到某页面:
但是这个不是让你瞎跳转到外面页面的,而是设置跳转到自己的页面。这个走的是url里面的路径。
那么到此为止知道 render 与 redirect 都是跳转页面的,有什么不同呢?
先看render :
跳转成功之后:
再来看 redirect 的:
两者的区别在于,网址不一样了,render跳转了还是原来的网址。而 redirect 的则是新网址。(特别做注册登录页面的时候需要注意)
看看redirect 的执行路径:
所以说,redirect 走的是urls路由里面的路径。
注意:这里有个特别要注意的地方,(卡了博主很久,由于看的是django2的视屏,跟3不同)由于跳转的是login页面,所以:
这里需要用 re_path ,就是这里卡了我很长时间,如果用的是path则会报错,原因暂时不清楚。
二、Template基础
1、把python语言渲染到前端页面
a、变量(使用双大括号来引用变量):
语法格式: {{var_name}}
>>> python manange.py shell (进入该django项目的环境)
>>> from django.template import Context, Template
标准写法:
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
输出:
'My name is Stephane.'
同一模板,多个上下文,一旦有了模板对象,你就可以通过它渲染多个context,无论何时我们都可以像这样使用
同一模板源渲染多个context,只进行一次模板创建然后多次调用render()方法渲染会更为高效:
#低级(下面这种写法会创建三个模板,没必要):
for name in ('John', 'Julie', 'Pat'):
t = Template('Hello, {{ name }}')
print t.render(Context({'name': name}))
#高级(一个模板解决!):
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
print t.render(Context({'name': name}))
Django 模板解析非常快捷。 大部分的解析工作都是在后台通过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎形成鲜明对比,那些引擎承担了 XML 解析器的开销,且往往比 Django 模板渲染引擎要慢上几个数量级。
from django.shortcuts import render,HttpResponse
from django.template.loader import get_template #记得导入
import datetime
from django.template import Template,Context
# def current_time(req):
#原始的视图函数
# now=datetime.datetime.now()
# html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now
# return HttpResponse(html)
# def current_time(req):
#django模板修改的视图函数
# now=datetime.datetime.now()
# t=Template('<html><body>现在时刻是:<h1 style="color:red">{{current_date}}</h1></body></html>')
#t=get_template('current_datetime.html')
# c=Context({'current_date':now})
# html=t.render(c)
# return HttpResponse(html)
#另一种写法(推荐)
def current_time(req):
now=datetime.datetime.now()
return render(req, 'current_datetime.html', {'current_date':now})
2、深度变量的查找(万能的句点号)
之前我们使用的都是字符串,其实还能使用列表,字典之类的数据类型。
还能通过 . 来取得想要的信息:
这里面没有索引的概念,想要取得数据都是通过 . 来取,包括什么 name ,age 都是通过 点 来获取。包括类也是,类实例出来的对象也是通过 点 来获取数据。
3、filter——变量的过滤器的使用
语法格式: {{ obj | filter:param }}
1 add : 给变量加上相应的值
2 addslashes : 给变量中的引号前加上斜线
3 capfirst : 首字母大写
4 cut : 从字符串中移除指定的字符
5 date : 格式化日期字符串
6 default : 如果值是False,就替换成设置的默认值,否则就是用本来的值
7 default_if_none: 如果值是None,就替换成设置的默认值,否则就使用本来的值
这个就相当于py的内置函数。
举些简单的例子:
cut:
date:
加上 date 之后:
a、safe
问题:如果我们此时 传送一个 a 标签过来,显示的会是a标签的形式吗?
结果是不能,只是一个字符串。
打开F12查看,看起来也没有问题:
只是为了安全起见,不是所有传过来的内容都会渲染成页面显示,得加一个 safe:
此时才能渲染成 a 标签:
同一个效果:autoescape
效果是一样的。
b、其它
字符串切片:
URL编码:
取得一个URL,对它进行编码,得到的是编码之后的内容。
4、标签(tag)的使用(使用大括号和百分比的组合来表示使用tag)
a、if 与 else 的使用
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容
{% if num >= 100 and 8 %}
{% if num > 200 %}
<p>num大于200</p>
{% else %}
<p>num大于100小于200</p>
{% endif %}
{% elif num < 100%}
<p>num小于100</p>
{% else %}
<p>num等于100</p>
{% endif %}
# {% if %} 标签接受and,or或者not来测试多个变量值或者否定一个给定的变量
# {% if %} 标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:
{% if obj1 and obj2 or obj3 %}
使用的规则跟普通的没啥区别,只是需要大括号与百分号。(切记结尾要写 endif )
b、for的使用
{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
{% for obj in... %}
...
{% endfor %}
使用的方法跟普通的没啥区别,但有其它的需要注意:
forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1:
这种打印出来的名字,前面会有数字跟着,默认从1开始:
如果想要从0开始计数,则这么写:
forloop.counter0
如果想要数字从最后往前计数:
forloop.revcounter
forloop.revcounter0
5,forloop.first当第一次循环时值为True,在特别情况下很有用:
{% for object in objects %}
{% if forloop.first %}
<li class="first">
{% else %}
<li>{% endif %}
{{ object }}
</li>
{% endfor %}
forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了。
如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它。
Django会在for标签的块中覆盖你定义的forloop变量的值。
在其他非循环的地方,你的forloop变量仍然可用。
最后一个:
{% empty %}
当用户查找某个东西,遍历了数据库之后都没有,这时候需要告诉用户,你查找的东西不存在,此时就可以用 empty:
c、csrf_token标签
用于生成csrf_token的标签,用于防治跨站攻击验证。
这里前面form表单 POST提交时就是这个问题。
加入个csrf_token就能正常访问网页了。
其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
打开F12就可以看到:
这相当于一把钥匙,一张身份证,只有带着这个访问Django,才能提交POST数据。第一次访问页面的时候,就已经返回了这个东西了,只有带着这个身份证提交,才能正常提交。Django先会取这一部分的键值对,如果符合才会接收数据。(这个东西的安全机制也不高,但至少也有一点。没有什么安全机制是绝对安全的)
d、{% with %}——用更简单的变量名替代复杂的变量名
如果后端传过来的变量名字太长,可以起一个短一点的名字。
{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}
e、{% verbatim %}——禁止render
{% verbatim %}
{{ hello }}
{% endverbatim %}
如果想使用的是文本,而不是变量,就使用这个。这时渲染出来的就是 hello 这个文本,而不是 hello 变量。
f、{% load %}——加载标签库
f(α)、自定义过滤器 filter(注意:只能返回两个参数,多一个都不行)
步骤很严格,必须按照步骤来:
(1)、在app中创建templatetags模块(必须的)
(2)、创建任意 .py 文件,如:my_tags.py
from django import template
from django.utils.safestring import mark_safe
register = template.Library() #register的名字是固定的,必须用这个名字!!!
@register.filter
def filter_multi(v1,v2):
return v1 * v2
@register.simple_tag
def simple_tag_multi(v1,v2):
return v1 * v2
@register.simple_tag
def my_input(id,arg):
result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
return mark_safe(result)
(3)、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}
(4)、使用simple_tag和filter(如何调用)
成功
(5)、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
f(β)、自定义标签
注意:自定义标签与自定义过滤器都是放在此文件下,区别在于你的语法糖是filter还是simple_tag:
注意:标签Tag用的是 {% … %},且可以传任意多个参数,但是不能用在控制语句里!
过滤器 filter 用的是 {{ … }},但会限制参数
g、extend——模板继承
-------include 模板标签
在讲解了模板加载机制之后,我们再介绍一个利用该机制的内建模板标签: {% include %} 。该标签允许在(模板中)包含其它的模板的内容。 标签的参数是所要包含的模板名称,可以是一个变量,也可以是用单/双引号硬编码的字符串。 每当在多个模板中出现相同的代码时,就应该考虑是否要使用 {% include %} 来减少重复。
-------extend(继承)模板标签
到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用 Django 模板系统来创建整个 HTML 页面。 这就带来一个常见的 Web 开发问题: 在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?
解决该问题的传统做法是使用 服务器端的 includes ,你可以在 HTML 页面中使用该指令将一个网页嵌入到另一个中。 事实上, Django 通过刚才讲述的 {% include %} 支持了这种方法。 但是用 Django 解决此类问题的首选方法是使用更加优雅的策略—— 模板继承 。
本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
比如我们做一个学生管理系统,通常布局是下面这种:
可以看到有两处地方是不变的,点击左边的链接,右边的内容会变,如果要做多个页面,这两处代码要经常复制来复制去吗?
这时候就需要用到,模板继承——extend(这个继承跟类的继承没有任何关系!)
说明:
我们想要上边与左边一样,右边不一样,经常改,这时候先写好一个首页:base.html:
在经常要改的区域,放置一个盒子,把内容放置进去:{% block “name” %}
页面显示与之前没有区别。
这时我们再创建一个页面,继承首页base.html,且不需要复制代码,之后可以看到页面一模一样:
然后操作跟之前一样,弄个盒子出来,就可以打其它内容:
可以看到,达到我们想要的效果,且代码量少非常多:
如果想加样式,就这样:
如果想要拿到父类盒子的内容,使用super :
以下是使用模板继承的一些诀窍:
<1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
<2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因
此你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子
越多越好。
<3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出
父模板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
<4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是
双向的。也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板
中出现了两个相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
还有之前引入jq文件时使用过的 {% load static %},加入这个之后:
可以直接把其它网页的内容、样式搬过来:
应用场景:
比如某个热门的东西,加入广告等。放置在右边小区域。