Django---MTV和MVC的了解,Django的模版语言变量和逻辑,常见的模板语言过滤器,自定义过滤器,CSRF了解,Django的母版(继承extends,块block,组件include,静态文件的加载load static),自定义simple_tag和inclusion_tag
Django---MTV和MVC的了解,Django的模版语言变量和逻辑,常见的模板语言过滤器,自定义过滤器,CSRF了解,Django的母版(继承extends,块block,组件include,静态文件的加载load static),自定义simple_tag和inclusion_tag
一丶MTV和MVC
MTV和MVC是一种软件架构,实现功能一样
MTV:在Django框架中使用
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
MVC:软件开发规范
MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller),具有耦合性低、重用性高、生命周期成本低等优点。
M: model 模型 操作数据库
V: view 视图 展示页面 HTML
C: controller 控制器 调度 业务逻辑
二丶常用语法
在Django框架模板中存在两种特殊的标记:
{{ 变量 }} : 表示获取变量的值
{% 逻辑 %} : 表示逻辑相关操作
变量:
{{ 变量 }},由字母和下划线组成.
. (点) 在模版语言中有特殊的意义,可获取对象的属性值,也可调用对象的方法.
#
def index(request):
res = {
# 传数字
'num': 123,
# 传字符串
'string1': '中文字符',
'string2': 'abcd',
# 传列表
'lis': ['熊大', '熊二', '熊三'],
# 传字典
'dic': {'name': '张哥', 'age': 33},
# 传对象
'p1': Person('Pig', 32)
}
return render(request, 'index.html', res)
# html页面
<h1>使用 { {变量} } 展示数据</h1>
<p>{{ num }}</p>
<p>{{ string1 }}</p>
<p>{{ string2 }}</p>
# <!--支持.的形式根据索引进行取值-->
<p>{{ string2.0 }}</p>
<p>{{ lis }}</p>
# <!-- 列表也支持.的形式根据索引进行取值 -->
<p>{{ lis.1 }}</p>
# <!--支持字典的所有方法,不需要加(),也支持.的形式取键对应的值-->
<p>{{ dic }}</p>
<p>{{ dic.name }}</p>
<p>{{ dic.keys }}</p>
<p>{{ dic.values }}</p>
# <!--对象单独的是内存地址,-->
<p>{{ p1 }}</p>
# <!--对象的属性-->
<p>{{ p1.name }}</p>
<p>{{ p1.age }}</p>
# <!--对象的方法,不需要加()-->
<p>{{ p1.talk }}</p>
# <!--若变量不存在,不会报错,得到是一个空的字符串.-->
<p>{{ xxx }}</p>
#PS:
当模板系统遇到一个(.)时,会按照如下的顺序去查询:
1.在字典中查询
2.属性或者方法
3.数字索引
{# .操作只能调用不带参数的方法 #}
{{ person_list.0.dream }}
Filter过滤器:
Django提供过滤器,对展示的字符串进一步筛选
语法: {{ value|filter_name:参数 }}
注意: ':'左右没有空格,出现空格就报错
### default 默认
# 语法:{{ value|default:"nothing"}}
# value的值没有传递,或者为空类型/None时,都会调用default默认值
# 一旦settings配置文件设置了:TEMPLATES的OPTIONS可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用.
# ps:调用string_if_invalid的优先级高于default,如果设置的变量不存在,调用string_if_invalid对应的值
<p>
{{ xxx|default:'aaa' }}
</p>
### filesizeformat 格式化数据大小(例如 '13 KB', '4.1 MB', '102 bytes',最大到PB)
# 语法:{{ value|filesizeformat }}
<p>
{{ 1024|filesizeformat }} #1.0 KB
</p>
### add 给变量做 +法,也具有拼接效果. 字符串拼接数字,列表拼接列表
# 语法:{{ value|add:"2" }}
<p>
{{ num|add:"2" }} # num=10 加2--->12
</p>
<p>
{{ lis|add:lis}} #列表拼接
</p>
<p>
{{ string1|add:'123456'}} # 字符串拼接数字
</p>
### lower 大写
# 语法:{{ value|lower }}
<p>
{{ string2|lower }}
</p>
### upper 大写
# 语法: {{ value|upper}}
<p>
{{ string2|upper }}
</p>
### title 标题,首字母大写
# 语法:{{ value|title }}
<p>
{{ string2|title }}
</p>
### ljust 左对齐, rjust 右对齐 ,center 居中
#语法:
"{{ value|ljust:"10" }}"
"{{ value|rjust:"10" }}"
"{{ value|center:"15" }}"
<p>
"{{ string1|ljust:"10" }}"
<br>
"{{ string1|rjust:"10" }}"
<br>
"{{ string1|center:"1" }}"
</p>
### length 获取数据的长度
# 语法: {{ value|length }}
<P>
{{ string1|length }}
</P>
### slice 切片 , 支持正向 也支持反向
# 语法:{{value|slice:"2:-1"}}
<p>
{{ lis }}
{{ lis|slice:'0:2' }} # 切除来两个
{{ lis|slice:'-1::-1' }} # 反向切出来所有
</p>
### first 取第一个元素
# 语法: {{ value|first }}
<p>
{{ string1 }}
{{ string1|first }} # 取第一个元素
</p>
### last 取最后一个元素
# 语法: {{ value|last }}
<p>
{{ string1 }}
{{ string1|last }} # 取第一个元素
</p>
### join 字符串拼接列表
# 语法: {{ value|join:" // " }}
<p>
{{ lis|join:'^^' }}
</p>
### truncatechars 字符串字符多于指定的字符数量,会被截断。截断的字符串将以省略号(“...”)结尾.
# 参数:截断的字符个数
# 语法:{{ value|truncatechars:9}}
<p>
{{ '难念的经爱上空间的撒谎加括号大数据库很快就打'|truncatechars:10 }} # 字符分隔
</p>
<p>
{{ '难念的 经爱上 空间的 撒谎加括 号大数据库很快就打'|truncatewords:3 }} #空格分隔,
</p>
### date 日期格式化
# 语法: {{ value|date:"Y-m-d H:i:s"}}
<p>
{{ now|date:'Y-m-d H:i:s' }} # 2019-08-28 15:45:50
</p>
# 当在settings配置文件设置以下参数时,就会更改默认时间显示的格式.就可以达到和date一样的效果
USE_L10N = False
DATETIME_FORMAT = 'Y-m-d H:i:s'
<p>
{{ now }}
</p>
### safe 告诉django不需要转义
# 文字叙述:👇
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
# 语法:{{ value|safe }}
'jjss':'<script> for (var i=0 ;i<5;i++){alert("123")}</script>'
{{ jjss|safe }} # 告诉浏览器这是安全的代码
{{ jjss }} # Django这个代码当做字符串处理 <script> for (var i=0 ;i<5;i++){alert("123")}</script>
# 或者使用mark_save()方法
from django.utils.safestring import mark_safe
'jjss':mark_safe('<script> for (var i=0 ;i<5;i++){alert("123")}</script>')
自定义过滤器:
1.在app目录下创建一个名为:templatetags的包
2.自定义函数
# -*-coding:utf-8-*-
# Author:Ds
from django import template #
register=template.Library() # 注册 , 名字必须是register
@register.filter # 装饰器.这个函数编程一个过滤函数
def my_upper(value,arg=None):
return value.upper()
@register.filter
def my_sum(value,arg=None):
print(value,type(value))
if type(value)==str:
value=value+str(arg)
elif type(value)==int:
value=int(value)+arg
return value
@register.filter(name="addSB") # name属性代表重新命名
def add_sb(value):
return "{} SB".format(value)
3.在模版页面使用
#### 使用流程
# {# 先导入我们自定义filter那个文件 #}
# {% load app01_filters %}
# {# 使用我们自定义的filter #}
# {{ somevariable|fill:"__" }}
# {{ d.name|addSB }}
# 具体如下:下
<h1>自定义过滤器</h1>
<!--加载myTags py文件-->
{% load myTags %}
{{ string2|my_upper }}
<!-- 加法 -->
{{ num|my_sum:2 }}
<!-- 减法 -->
{{ num|my_subtraction:2 }}
<!-- 乘法 -->
{{ num|my_multiplication:2 }}
<!-- 除法 -->
{{ num|my_division:2 }}
模版中的逻辑语法
模版语言中的for的使用
# for语法:
{% for el in el_list %}
{{el}}
{% endfor %}
# for的一些参数
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(到1结束)
forloop.revcounter0 当前循环的倒序索引值(到0结束)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
for ... empty
# for ... empty 语法:
{% for el in el_list %}
{{el}}
{% empty %} # 当循环的东西不存在或者为空时,显示empty的内容
<li>显示为空</li>
{% endfor %}
if ... elif ... else
# 语法:
{% if user_list %}
用户人数:{{ user_list|length }}
{% elif black_list %}
黑名单数:{{ black_list|length }}
{% else %}
没有用户
{% endif %}
#PS :
在模板中支持的语法有:and 、or、==、>、<、!=、<=、>=、in、not in、is、is not
不支持连续判断: if a>b>c ### 不支持
不支持算术运算: if 1+2==3 ### 不支持
with 给变量起名字
{% with p1.name as al %} # 可以as
{{ al }}
{% endwith %}
{% with al=p1.name %} # 也可以给复杂的变量名 重新命名成 简单的变量名
{{ al }}
{% endwith %}
{% csrf_token %} 防止跨站请求伪造
# 防止跨站请求伪造
<form action="" method="post">
# name="csrfmiddlewaretoken"
{% csrf_token %} # 会添加一个隐藏的input框. 当提交数据是,协同csrf令牌一同提交.
<input type="text" name="name">
<button>提交</button>
</form>
三丶母版
即定义公共的部分
# base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书管理系统</title>
{# 加载静态资源 #}
{% load static %}
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/dashboard.css' %}">
<link rel="icon" href="/static/imgs/QQ图片20190829155013.jpg">
<style>
.table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {
vertical-align: middle;
}
</style>
</head>
<body>
{# 组件 #}
{% include 'nav.html' %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="{% block pub_cls %}{% endblock %}"><a href="/publish_list/">出版社管理 </a></li>
<li class="{% block book_cls %}{% endblock %}"><a href="/book_list/">图书管理</a></li>
<li class="{% block aut_cls %}{% endblock %}"><a href="/author_list/">作者管理</a></li>
</ul>
</div>
{% block content %}
<h1>内容哦</h1>
{% endblock %}
</div>
</div>
<script src="{% static 'js/jquery-1.11.1.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script>
{% block js %}
{% endblock %}
</script>
</body>
</html>
继承母版
子页面继承母版,减少代码的重复量
# 语法:
{% extends 'base.html'%}
# 示例:👇
{% extends 'base.html' %} # 继承母版
{% block aut_cls %}
active
{% endblock %}
块(block)
子页面继承母版,可以通过block块重新写
# 语法:
{% block 变量名%}
#内容
{% endblock %}
# 示例:👇
{% block content %} # 替换母版 content变量 的内容
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h2 class="sub-header">作者列表</h2>
<div class="table-responsive">
<a href="/author_add/" class="btn btn-info btn-sm">添加作者</a>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>#</th>
<th>序号</th>
<th>作者ID</th>
<th>作者姓名</th>
<th>著作</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for author in all_author %}
<tr>
<td>
<input type="checkbox">
</td>
<td>{{ forloop.counter }}</td>
<td>{{ author.pk }}</td>
<td>{{ author.username }}</td>
<td>
{% for book_obj in author.books.all %}
<< {{ book_obj.bname }}>>
{% endfor %}
</td>
<td>
<a class="btn btn-warning btn-sm" href="/author_edit?pk={{ author.pk }}">编辑</a>
<a class="btn btn-danger btn-sm" href="/author_del?pk={{ author.pk }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% include 'page.html' %}
</div>
</div>
{% endblock %}
组件:
将一段代码单独放在页面上.
# 语法:
{% include 'nav.html' %}
{% include 'nav.html' %}
{% include 'leftmenu.html' %}
静态文件:
加载静态资源,可以自动去拼接/static/路径, 当修改settings文件配置时,load static 始终获取的是你静态资源的'别名'.
### 引用静态文件
{% load static %} # 自动寻找到static对应的静态资源.
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/dashboard.css' %}">
### 引用js
{% load static %} # 自动寻找到static对应的静态资源.
<script src="{% static "mytest.js" %}"></script> #'/static/mytest.js'
### 多出引用同一个资源时, 可以重新命名.
{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>
使用'get_static_prefix' 拼接路径
## get_static_prefix 获得静态资源的前缀 ,如:'/static/'
{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" /> # 后续手动拼接路径
自定义simpletag
@register.simple_tag
def num_my(*args,**kwargs): # 给的参数限制
return '_'.join(args) + "*".join(kwargs.values()) #返回的值是已经处理过的.
# 页面使用
{% load my_Tags %} # 加载 my_Tags自定义文件
{% num_my 'a' 'b' 'c' 'd' %} # 参数必须加引号
自定义inclusion_tag
自定义include组件
@register.inclusion_tag('page.html') # 必须指定一个页面
def page(num): # 参数不限制
'''
num 是页数
:param num:
:return:
'''
return {'num':range(1,num+1)} # 必须是返回一个字典. 这个字典的参数还是传到page.html页面中使用
### 页面使用
{% load my_Tags %} # 加载 my_Tags自定义文件
{% page 10 %} # 也会将页面加载出来
inclusion_tag面试题
### 面试题:
模板中使用{% sqr_list 3 %},生成如下的dropdown list 控件(下拉菜单)
key text
1 1的平方是1
2 2的平方是4
3 3的平方是9
请写出sqr_list的实现
##### my_Tags
from django import template
register=template.Library() # 注册
@register.inclusion_tag('homework.html')
def sqr_list_DEMO(num):
data=[f'{i} ---{i}的平方是{i**2}' for i in range(1,num+1)]
return {'data':data}
#### homework.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
</head>
<body>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
Dropdown
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% for foo in data %}
<li><a href="#">{{ foo }}</a></li>
{% endfor %}
</ul>
</div>
</body>
<script src="{% static 'js/jquery-1.11.1.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</html>
### 展示页面
{% load myTags %} # 加载 mytag文件
{% sqr_list_DEMO 10 %} # 执行 sqr_list_DEMO