Django的模板渲染,继承css
1、语法html
两种特殊符号:django
{{ }} 和 {% %}后端
变量相关的用{{ 变量 }},逻辑相关的用{% 逻辑 %}。浏览器
2、变量缓存
在Django的模板语言中按此语法使用:{{ 变量名 }}安全
当模版引擎遇到一个变量,它将计算这个变量,而后用结果替换掉它自己。 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号app
urls.py 先配置路径: url(r'^index/', views.index), views.py from django.shortcuts import render,HttpResponse,redirect def index(request): num = 100 name = 'alex' food_list = ['蒸熊掌','烧花鸭','烧子鹅'] dic = {'year':2019,'month':7,'day':17} class Animal: def __init__(self): self.kind = 'dog' def color(self): return 'black' a = Animal() return render(request,'index.html',{'num':num,'name':name,'food_list':food_list,'dic':dic,'a':a}) # 经过字典的形式传把值给html文件 return render(request,'index.html',locals()) # locals() 获取函数内部全部变量的值,并加工成{'变量名':'变量值'....}这样一个字典 index.html <p>{{ num }}</p> <p>{{ name }}</p> <p>{{ food_list }}</p> <p>{{ dic }}</p> <p>{{ a }}</p> <p>{{ a.kind }}</p> <p>{{ a.color }}</p>
注意:xss
3、过滤器编辑器
在Django的模板语言中,经过使用 过滤器 来改变变量的显示。
过滤器的语法: {{ value|方法名:参数 }} 使用管道符"|"来应用过滤器 ,冒号":"来链接参数
Django的模板语言中提供了大约六十个内置过滤器
length
获取数据长度,没参数,做用于字符串和列表 {{ value|length }} <p>{{ food_list|length }}</p>
default
默认值,有参数,若是一个变量是false或者为空,使用给定的默认值。 不然,使用变量的值 <p>{{ xx|default:'啥也没有' }}</p> # views若没有传过来xx的值,因此就会显示设置的默认值
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等) # 好比在views中 size = 123456 <p>{{ size|filesizeformat }}</p> # 此时格式转换成 120.6 KB
slice
切片 ,跟字符串、列表的切片方法同样 {{value|slice:"2:-1"}} <p>{{ name|slice:':3' }}</p> # 0可省略
date
时间格式化显示 # 好比在views中 ntime = datetime.datetime.now() <p>{{ ntime|date }}</p> # July 17, 2019 <p>{{ ntime|date:"Y-m-d H:i:s"}}</p> # 2019-07-17 16:27:55
truncatechars
字符截断 若是字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。 参数:截断的字符数 # 好比在views中 name = 'alexdsb' <p>{{ name|truncatechars:7 }}</p> # alex... #注意:最后那三个省略号也是7个字符里面的,也就是这个7截断出来的是4个字符+3个省略号
truncatewords
单词截断 在必定数量的字后截断字符串,是截多少个单词 # 好比在views中 word = 'hello girl hi baby yue ma' <p>{{ word|truncatewords:4 }}</p> # hello girl hi baby ... # 单词截断,截的是多少个单词,省略号不算
cut
移除value中全部的与给出的变量相同的字符串 # 好比在views中 word = 'hello girl hi baby yue ma' <p>{{ words|cut:'i' }}</p> # hello grl h baby yue ma
join
使用字符串链接列表,{{ list|join:', ' }},就像Python的str.join(list) # 好比在views中 food_list = ['蒸熊掌','烧花鸭','烧子鹅'] <p>{{ food_list|join:'+' }}</p> # 蒸熊掌+烧花鸭+烧子鹅
safe
将 字符串识别成标签
假如在用户评论的时候写了一段js代码,若是不转义,js代码就会执行了,浏览器会一直弹窗等等,这叫作xss攻击。Django的模板中在进行模板渲染的时候,为了安全,会对HTML标签和JS等语法标签进行自动转义 。在Django中关闭HTML的自动转义有两种方式,若是是一个单独的变量咱们能够经过过滤器“|safe”的方式告诉Django这段代码是安全的没必要转义。
# 好比在views中 tag = '<a href="http://www.baidu.com">百度</a>' <p>{{ tag }}</p> # <a href="http://www.baidu.com">百度</a> 只会当成字符串 <p>{{ tag|safe }}</p> # 显示了一个百度的a标签
4、标签Tags
标签看起来像是这样的: {% tag %}
经过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。
一些标签须要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。
for循环标签
for循环普通的方法
循环一个字典: views dic = {'year':2019,'month':7,'day':17} html {% for key,value in dic.items %} <li>{{ key }} -- {{ value }}</li> {% endfor %} 循环一个列表: views food_list = ['蒸熊掌','烧花鸭','烧子鹅'] html <ul> {% for food in food_list %} <li>{{ food }}</li> {% endfor %} </ul> # 利用 reversed 反向完成循环 <ul> {% for food in food_list reversed %} <li>{{ food }}</li> {% endfor %} </ul>
for循环其余方法
forloop.counter 当前循环的索引值(从1开始),forloop是循环器,经过点来使用功能 forloop.counter0 当前循环的索引值(从0开始) forloop.revcounter 当前循环的倒序索引值(从1开始) forloop.revcounter0 当前循环的倒序索引值(从0开始) forloop.first 当前循环是否是第一次循环(布尔值) forloop.last 当前循环是否是最后一次循环(布尔值) forloop.parentloop 本层循环的外层循环的对象,再经过上面的几个属性来显示外层循环的计数等,好比:forloop.parentloop.counter
注意:循环序号能够经过{{forloop}}显示,必须在循环内部用
{% for key,value in dic.items %} {{ forloop.counter }} # 从1开始计数,好比dic有3个键值对,就1,2,3 <li>{{ key }} -- {{ value }}</li> {% endfor %} {% for key,value in dic.items %} {{ forloop.counter0 }} # 从0开始计数,好比dic有3个键值对,就0,1,2 <li>{{ key }} -- {{ value }}</li> {% endfor %} {% for key,value in dic.items %} {{ forloop.revcounter }} # 倒序直到1计数,好比dic有3个键值对,就3,2,1 <li>{{ key }} -- {{ value }}</li> {% endfor %} {% for key,value in dic.items %} {{ forloop.revcounter0 }} # 倒序直到0计数,好比dic有3个键值对,就2,1,0 <li>{{ key }} -- {{ value }}</li> {% endfor %} {% for key,value in dic.items %} {{ forloop.first }} # 判断是否是第一次循环,显示bool值 <li>{{ key }} -- {{ value }}</li> {% endfor %} {% for key,value in dic.items %} {{ forloop.last }} # 判断是否是第一次循环,显示bool值 <li>{{ key }} -- {{ value }}</li> {% endfor %} forloop.parentloop示例: 循环views中的列表 d1 = [['春天','夏天','秋天','冬天'],['雨水','清明']] {% for dd1 in d1 %} {% for ddd1 in dd1 %} {{ forloop.parentloop.counter }} {{ forloop.counter }} <div>{{ ddd1 }}</div> {% endfor %} {% endfor %} 1 1 父辈的循环计数是1,本身的循环计数是1 春天 1 2 父辈的循环计数是1,本身的循环计数是2 夏天 1 3 父辈的循环计数是1,本身的循环计数是3 秋天 1 4 父辈的循环计数是1,本身的循环计数是4 冬天 2 1 父辈的循环计数是2,本身的循环计数是1 雨水 2 2 父辈的循环计数是2,本身的循环计数是2 清明
for .... empty
for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,能够有所操做。
好比在views中并无给出 person_list,此时html中 {% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %} 由于没有找到这个列表,页面就会显示empty中的内容 sorry,no person here 若是有 person_list = [{'name':'dazhuang'},{'name':'taibai'},{'name':'alex'}] 此时页面就会显示:dazhuang、taibai、alex
if标签
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格
注意:
Django的模板语言中属性的优先级大于方法(了解)
def xx(request):
d = {"a": 1, "b": 2, "c": 3, "items": "100"}
return render(request, "xx.html", {"data": d})
如上,咱们在使用render方法渲染一个页面的时候,传的字典d有一个key是items而且还有默认的 d.items() 方法,此时在模板语言中: {{ data.items }},默认会取d的items key的值,即取d的items键对应的值100,而不是执行items方法
{% if num > 100 or num < 0 %}
什么鬼
大佬真猛
凑活吧
假如views中传过来 num = 100,则页面显示 大佬真猛
with标签
使用一个简单地名字缓存一个复杂的变量,多用于给一个复杂的变量起别名,注意等号左右不要加空格
假如views中有这样一个列表 person_list = [{'name':'dazhuang'},{'name':'taibai'},{'name':'alex'}],我想把 alex 取出来 两种方式: 方式一: {% with name=person_list.2.name %} # 注意等号两边没有空格 {{ name }} # 只能在with语句体内用,外边就很差使了 {% endwith %} 方式二: {% with person_list.2.name as name %} {{ name }} {% endwith %}
csrf_token标签
当以post提交表单的时候,会报错,咱们以前的解决办法是在settings里面的中间件配置里面把一个csrf的防护机制给注销了 ,而自己是不该该注销的,不让本身的操做被forbiden,经过csrf_token标签就能搞定。 这个标签用于跨站请求伪造保护 在页面的form表单里面(注意是在form表单里面)任何位置写上{% csrf_token %},这个东西模板渲染的时候替换成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隐藏的,这个标签的值是个随机字符串,提交的时候,这个东西也被提交了,首先这个东西是咱们后端渲染的时候给页面加上的,那么当你经过我给你的form表单提交数据的时候,你带着这个内容我就认识你,不带着,我就禁止你,由于后台咱们django也存着这个东西,和你这个值相同的一个值,能够作对应验证是否是我给你的token,就像一个咱们后台给这个用户的一个通行证,若是你用户没有按照我给你的这个正常的页面来post提交表单数据,或者说你没有先去请求我这个登录页面,而是直接模拟请求来提交数据,那么我就能知道,你这个请求是非法的。
好比:
views: def index(request): if request.method == 'GET': return render(request,'index.html') else: return HttpResponse('成功了呢!!!') index.html: <form action="" method="post"> 内容:<input type="text"> <button>提交</button> </form> # 此时,咱们没有加{% csrf_token %},也没注销settings里的防护机制,则网页会报错操做被forbiden
加上 {% csrf_token %} 试一试:
views: def index(request): if request.method == 'GET': return render(request,'index.html') else: return HttpResponse('成功了呢!!!') index.html: <form action="" method="post"> {% csrf_token %} 内容:<input type="text"> <button>提交</button> </form> # 此时,咱们就能够正常的拿到post请求后执行的页面了
5、模板继承
语法: {% extends 'base.html' %} ,可预留钩子block 模版继承就是建立一个基本的“骨架”模版,它包含站点中的所有元素,而且能够定义可以被子模版覆盖的 blocks 。 当咱们写许多网页的时候,发现部分网页里面的许多内容都很相似,这样咱们就把类似的内容都拿出来,制做成一个母版,须要的页面来继承,这样就会节省许多的重复代码。 制做这样一个界面,输入127.0.0.1:8000/home/,访问首页,显示右边内容是home页面;点击菜单1时,跳转到menu1界面,右边显示menu1;菜单2和3同理;
先配置路径 urls:
from django.conf.urls import url
from app01 import views
urlpatterns = [ url(r'^home/', views.home), url(r'^menu1/', views.menu1), url(r'^menu2/', views.menu2), url(r'^menu3/', views.menu3), ]配置好首页路径home/,和三个菜单的路径
视图函数 views:
from django.shortcuts import render
def home(request): return render(request,'home.html') def menu1(request): return render(request, 'menu1.html') def menu2(request): return render(request, 'menu2.html') def menu3(request): return render(request, 'menu3.html')写首页和三个菜单的视图函数
咱们须要创建四个html文件:一个首页的home.html,和三个菜单的html
当咱们不用模板继承的方法时,由于导航栏和菜单栏四个文件都是同样的,因此四个文件的代码大部分同样,这样的重复代码就过多了
以首页 home为例,三个菜单的基本同样
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>模板继承</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; height: 40px; line-height: 40px; } .nav a{ color: white; text-decoration: none; padding: 0 50px; } .left-menu{ background-color: gray; color: white; height: 600px; width: 20%; float: left; } .left-menu a{ color: white; text-decoration: none; } ul{ margin: 0; padding: 0; } li{ padding-left: 75px; height: 50px; line-height: 50px; border: 1px solid black; } .content{ width: 80%; float: right; } .clearfix{ content: ''; display: block; clear: both; } </style> </head> <body> <div class="nav"> <a href="">外设首页</a> <a href="">鼠标专卖</a> <a href="">键盘专卖</a> <a href="">耳麦专卖</a> <input type="text"><button>搜索</button> </div> <div class="clearfix"> <div class="left-menu"> <ul type="none"> <li><a href="/menu1/">菜单1</a></li> <li><a href="/menu2/">菜单2</a></li> <li><a href="/menu3/">菜单3</a></li> </ul> </div> <div class="content"> home页面 只须要改这里,改为其余三个菜单对应的内容 </div> </div> </body> </html>
用模板继承来完成
先创建一个母版 base.html文件,把相同的内容放进来
<!DOCTYPE html>
</head> <body> <div class="nav"> <a href="">外设首页</a> <a href="">鼠标专卖</a> <a href="">键盘专卖</a> <a href="">耳麦专卖</a> <input type="text"><button>搜索</button> </div> <div class="clearfix"> <div class="left-menu"> <ul type="none"> <li><a href="/menu1/">菜单1</a></li> <li><a href="/menu2/">菜单2</a></li> <li><a href="/menu3/">菜单3</a></li> </ul> </div> <div class="content"> {% block content %} 这就是钩子 母版页面 {% endblock content %} </div> </div> </body> </html>
首页 home.html(其余三个菜单的html文件同理):
{% extends 'base.html' %} 继承的语法
{% block content %} 钩子,写本身的的内容,去替换母版钩子的内容 首页页面 {% endblock content %}
这样一样能完成以前的效果,而且节省的不少的代码
注意的点:
6、组件
语法:{% include 'navbar.html' %}
能够将经常使用的页面内容如导航条,页尾信息等组件保存在单独的文件中,而后在须要使用的地方,文件的任意位置按以下语法导入便可。
例如:有个导航栏的 nav.html 文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .c1{ background-color: red; height: 40px; } </style> </head> <body> <div class="c1"> <div> <a href="">xx</a> <a href="">dd</a> </div> </div> </body> </html>
此时有一个 test.html文件,直接嵌入以上导航栏的页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include 'nav.html' %} 组件的语法 <h1>xxxxxxxxxx</h1> </body> </html>
这样test.html文件没有写导航栏的代码,却依然拿到了导航栏
组件和插件的简单区别
组件是提供某一完整功能的模块,如:编辑器组件,QQ空间提供的关注组件 等。 而插件更倾向封闭某一功能方法的函数。 这二者的区别在 Javascript 里区别很小,组件这个名词用得很少,通常统称插件。
7、自定义标签和过滤器
自定义过滤器
在 my_tags.py 文件中建立自定义过滤器
from django import template # 先导入 template
register = template.Library() # register至关于一个注册器,名字是固定的,不可改变 @register.filter # 这样使用注册器,注意filter后不加括号 def my_filter(v1): # 不带参数的过滤器 s = v1 + '你真好' return s @register.filter # 这样使用注册器,注意filter后不加括号 def my_filter(v1,v2): # 带参数的过滤器(最多传递一个参数) s = v1 + '你真好' + v2 return s
urls配置好路径,views写好视图函数
urls:
url(r'^index/', views.index),
views: def index(request): name = 'alex' return render(request,'test.html',{'name':name})
在模板的文件templates 中建立的 test.html 文件,就能够经过引入使用了
{% load my_tags %}
{{ name|my_filter }} 页面显示:alex你真好
{% load my_tags %} {{ name|my_filter:'呵呵' }} 页面显示:alex你真好呵呵
注意:自定义的过滤器最多只能传递一个参数,多参数可考虑自定义标签
自定义标签
inclusion_tag
多用于返回html代码片断 ,能够将一个html文件先进行模板渲染,渲染完后,把html文件当成一个组件,放到你使用这个标签的地方
建立自定义的inclusion_tag
@register.inclusion_tag('test02.html')
def func(v1):
return {'data':v1} 此时v1接收的 l1 = [11,22,33]func的return数据,传给了test02.html,做为模板渲染的数据,将test02.htm渲染好以后,做为一个组件,生成到调用这个func的地方
创建test02.html,封装一些功能,至关于组件
8、静态文件配置
js、css、img等都叫作静态文件,那么关于django中静态文件的配置,咱们就须要在settings配置文件里面配置一些内容
在settings中配置:
STATIC_URL = '/static/' # 指定路径的别名
STATICFILES_DIRS = [ os.path.join(BASE_DIR,'jingtaiwenjian'), ]
调用静态文件:
在html文件中,想加入一个css的样式,有如下方法引入静态文件:
方式一: <link rel="stylesheet" href="/jingtaiwenjian/mycss.css"> 这样写是不对的,要用别名static <link rel="stylesheet" href="/static/mycss.css"> 方式二: {% load static %} <link rel="stylesheet" href="{% static 'mycss.css' %}"> 方式三: <link rel="stylesheet" href="{% get_static_prefix %}mycss.css">用别名 static 的优势:
{% static %}
引入一张图片: {% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!" /> 引用JS文件时使用: {% load static %} <script src="{% static "mytest.js" %}"></script> 某个文件多处被用到能够存为一个变量 {% load static %} {% static "images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img>
{% get_static_prefix %} 获取别名前缀的
{% load static %} <img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" /> 或者,用别名: {% load static %} {% get_static_prefix as STATIC_PREFIX %} <img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" /> <img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />