MVC框架 和 MTV框架
MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,
把软件系统分为三个基本部分:模型(Model)、视图(View) 和 控制器(Controller),
具有耦合性低、重用性高、生命周期成本低等优点。
Django的 MTV模式
Django框架的设计模式借鉴了MVC框架的思想,也是分成三部分,来降低各个部分之间的耦合性。
Django框架的不同之处在于它拆分的三部分为:Model(模型)、Template(模板)和 View(视图),也就是MTV框架。
1 | Model(模型):负责业务对象与数据库的对象(ORM) |
介绍Django框架时,可以说: Django框架类似MCV模式,不同的是他的模式成为MTV模式。
此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
Django 模板系统
常用语法
1 | 1. 只需要记两种特殊符号:{{ }}和 {% %} |
变量
1 | 在Django的模板语言中按此语法使用:{{ 变量名 }} |
1 | # views中的变量的例子: |
1 | <!--模板中支持的写法:--> |
Filters(过滤器)
1 | 在Django的模板语言中,通过使用 过滤器 来改变变量的显示。 |
1 | 注意事项: |
Django的模板语言中提供了大约六十个内置过滤器。
default
如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。
1 | <!--如果value没有传值或者值为空的话就显示nothing--> |
length
返回值的长度,作用于字符串和列表。
1 | <!--返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4--> |
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 ‘13 KB’, ‘4.1 MB’, ‘102 bytes’, 等等)。例如:
1 | <!-- 如果 value 是 123456789,输出将会是 117.7 MB。--> |
slice
切片
1 | {{value|slice:"2:-1"}} |
date
格式化
1 | {{ value|date:"Y-m-d H:i:s"}} |
safe
1 | Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。 |
1 | {#多用于文章评论时,放入的html连接或者其他恶意如死循环代码XSS攻击,跨站脚本攻击,做安全效验转义#} |
truncatechars
truncatechars 如果字符串字符多于指定的字符数量,那么会被截断。
截断的字符串将以可翻译的省略号序列(“…”)结尾。
参数:截断的字符数
1 | <p>{{ p_str|truncatechars:5 }}</p> |
自定义filter
1 | 自定义过滤器只是带有一个或两个参数的Python函数: |
自定义filter代码文件摆放位置:
1
2
3
4
5
6
7app01/
__init__.py
models.py
templatetags/ # 在app01下面新建一个package package:templatetags
__init__.py
app01_filters.py # 建一个存放自定义filter的文件
views.py编写自定义filter
1 | from django import template |
- 使用自定义filter
需要重启项目加载
1 | <hr> |
Tags
for循环
普通for循环
1 | <ul> |
for循环可用的一些参数:
1 | <p>for 循环 |
for … empty
1 | {% for book in book_list %} |
双层for循环
1 | <p>双层for循环</p> |
if判断
if,elif和else
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
1 | {% if user_list %} |
1 | <p>if ... elif ... else</p> |
1 | {% if name_list|length >= 3 %} |
with
定义一个中间变量,多用于给一个复杂的变量起别名,注意等号左右不要加空格
1 | <p>with</p> |
注释 和 注意事项
1 | {# ...注释... #} |
1 | 1. Django的模板语言不支持连续判断,即不支持以下写法: |
母版和继承
为什么要有母版和继承
html页面有重复的时候,把他们提取出来放到一个单独的html文件(比如:导航条和左侧菜单),
把多个页面公用的部分提取出来,放在一个母版页面里面,其他的页面只需要 继承 母版就可以了
具体使用的步骤
- 把公用的HTML部分提取出来,在项目目录templates中新建一个 base.html 基础页面,将内容放入。
1 |
|
- 在base.html 中,通过定义block,把每个页面不同的部分区分出来:
1 | {#专门替换css文件的块,别的页面没有用到#} |
- 在具体的页面中,先继承母版
1 | {% extends 'base.html' %} |
- 然后通过block名字去指定替换母版中相应的位置
1 | {% extends 'base.html' %} |
导航栏选中的判断方法
1 | <!--方法1:判断传进来的变量是否有值--> |
1 | <!--方法2:使用block--> |
专门替换CSS样式的块
1 | # 定义一个book_list_only.css文件 |
专门替换JS文件的块
1 | # 定义一个author_list_only.js 文件 |
使用母版和继承的注意事项
1 | 1. {% extends 'base.html' %} --> 母版文件:base.html要加引号, |
组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
什么时候用组件:重复的代码,包装成一个独立的小html文件。
- 单独提取导航条 成为小组件,把导航条单独写成一个nav.html
把base.html中的nav剪切分割到nav.html,里面的内容只放导航条的内容
1 | <nav class="navbar navbar-inverse navbar-fixed-top"> |
- 如何使用
在base.html中导入
1 | <body> |
- 在add_book.html中添加导航条
1 | {#加导航条#} |
静态文件路径的灵活写法
- 利用static方法帮我拼接静文件的路径
多用于base.html 母版中的css和js文件引入
1 | {% load static %} |
- 利用内置的get_static_prefix获取静态文件路径的别名,我们自行拼接路径
1 | {% load static %} |
- as 语法(一个路径多次用到,可以使用as保存到一个变量,后面直接使用变量代替具体路径
自定义的simple_tag
比filter高级一点点,它可以接收的参数大于2
1 | from django import template |
自定义的inclusion_tag
用来返回一段html代码(示例:返回ul标签)
- 定义阶段:
在app下新建:templatetags 目录(注意是Python包)
新建python文件 my_inclusion.py
1 | from django import template |
编辑要用到的ul.html
1
2
3
4
5<ul>
{% for ret in data %}
<li> {{ ret }}</li>
{% endfor %}
</ul>调用阶段:
1 | <!--# 要记得重启--> |
Django 视图系统
什么是视图系统
- 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。
- 视图view(接收请求,返回响应这一部分就叫视图,也可以叫处理函数)
CBV 和 FBV
- CBV( class base view 基于类的视图 )和FBV( function base view 基于函数的视图 )
例如将出版社的添加方法,修改为CBV 基于类的视图:
views.py添加:
1 | # CBV 出版社添加 |
1 | # FBV 出版社添加 |
- 使用CBV时,urls.py中也做对应的修改:
1 | # urls.py中 |
Request 对象 和 Response 对象
Request 对象
当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象。
Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
请求相关的常用值:1
2
3
4
5path_info 返回用户访问url,不包括域名
method 请求中使用的HTTP方法的字符串表示,全大写表示。
GET 包含所有HTTP GET参数的类字典对象
POST 包含所有HTTP POST参数的类字典对象
body 请求体,byte类型 request.POST的数据就是从body里面提取到的
常用属性:
1 | request.method # 获取请求的方法(GET,POST等) |
注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
1 | request.POST.getlist("hobby") |
上传文件示例
- urls.py
1 | # 上传文件 |
- views.py
1 | # 处理上传文件的函数 |
- upload_files.html
1 |
|
Response 对象
与由Django自动创建的HttpRequest对象相比,HttpResponse对象是我们的职责范围了。
我们写的每个视图都需要实例化,填充和返回一个HttpResponse。
HttpResponse类位于django.http模块中。
- 基础必备三件套
1 | HttpResponse --> 返回字符串内容 |
JsonResponse 对象
JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应。
urls.py
1 | # JsonResponse对象 |
views.py
1 | # json_test |
Django 路由系统
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。
你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
URLconf配置
- 基本格式:
1 | from django.conf.urls import url |
- 参数说明:
1 | 正则表达式:一个正则表达式字符串 |
正则表达式详解
- 基本配置
1 | # urls.py: |
- 注意事项:
1 | urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。 |
分组匹配
分组匹配:给视图函数传递位置参数
分组匹配和分组命名匹配不能混用,看需求使用哪一种1
2
3
4
5
6
7# urls.py
# 分组匹配()
url(r'^book/([0-9]{2,4})/([a-zA-Z]{2})/$', views.book),
# http://127.0.0.1:8000/book/12/ab/
# book() takes 1 positional argument but 3 were given
# 如果我们使用分组匹配,会将()分组匹配里面的值,当做参数发送给视图函数,函数中除了request,还需要接收()里面的参数
# 这种方式可以代替?id=1,地址栏传值
1 | # views.py |
分组命名匹配
分组命名:给视图函数传关键字参数
1 | # urls.py |
1 | views.py |
设置默认值
- 如果用户访问blog/ 那么我们默认返回num1,也就是blog的第一页
- 如果用户到这page100访问,那么我们直接返回对应的页面
- 返回的是blog/page具体第几页的blog,num=捕获的值,而不是num=1
1 | # urls.py中 |
分组匹配的使用
出版社删除 改为分组匹配
1 | # urls.py |
1 | # views.py |
1 | <a href="/del_publisher2/{{ publisher.id }}/">分组匹配删除</a> |
出版社修改 改为分组匹配
1 | # urls.py |
1 | # views.py |
1 | <a href="/edit_publisher2/{{ publisher.id }}/">分组匹配编辑</a> |
include 其他的URLconfs
- 我们现在所有的路由指向都是写在一个配置文件 project/urls.py
- 当我们的app有很多的时候,就需要分组管理
include 分流urls
- 执行命令
1 | D:\MyProject\test_0922>python manage.py startapp app02 |
- 在settings中添加配置,告诉Django我们添加了新的app
1 | INSTALLED_APPS = [ |
- 在app01中新建ursl.py
- 编辑2级路由app01/urls.py
1 | from django.conf.urls import url |
- 编辑1级路由project/urls.py
1 | from django.conf.urls import url,include |
include app02.urls
1 | # app02.urls |
1 | # app02.views |
1 | # project.urls |
命名URL和URL反向解析
- Templates里面创建多级目录
- templates
- car
- home.html
- house
- home.html
- car
- 编写urls.py 对应各自的路由:
1 | # project/urls.py |
1 | # app01/urls.py |
1 | # app02/urls.py |
- 编写views.py
1 | def home(request): |
1 | def home(request): |
- 编写html
1 | <h1>app01/home 这是卖车的首页</h1> |
1 | <h1>app02/home 这是卖房子的首页</h1> |
- 现在我们有了两个app并且都各自用有自己的路由和视图函数,返回各自的首页,并且在页面中都由a标签跳转
- 这个时候如果我们的urls的路径被修改了,相应的跳转也就无法访问,这是由于url被固定了
1 | url(r'^carcar/',include(app01_urls)), |
使用url反向解析来获取页面
- 一级路由解析
路由侧添加了别名:name=’别名’,html就可以动态调用url=’别名’
此功能可以防止url被修改,导致页面无法找到url路径
1 | # project.urls |
1 | # house/home.html |
- 二级路由,通过别名反向解析找到url
1 | # project/urls.py |
1 | # app01/urls.py |
1 | <a href="{% url 'car_home' %}">想买车点我</a> |
使用url反向解析,在视图views中跳转
- 一般views中的跳转使用redirect
1 | # project/urls |
1 | def home(request): |
- 根据别名找到跳转的url
1
2
3
4
5
6
7
def home(request):
from django.urls import reverse
# reverse 反向解析,根据别名找到跳转的url
# 会去urls里面找到对应的别名
redirect_url = reverse("json_test")
return redirect(redirect_url)
- 反向解析URL
- 本质上就是给url匹配模式起别名,然后通过别名拿到具体的url地址
- 如何使用
- 在url匹配模式中,定义name=’别名’
- 在模板语言里使用 url ‘别名’
- 在视图函数里使用
1 | from django.urls import reverse |
使用url反向解析,加上参数跳转
- 当url里面含有参数的时候,别名如何解析呢?
1 | app01/urls |
1 | # 在反转的时候带参数 |
2.在模板语言中,测试带参数的url反向解析
1 | <p>测试带参数的url反向解析: |
把编辑按钮的连接改成反向解析URL形式
- 适用于分组匹配
1
2# url分组匹配,括号里的值会传给函数
url(r'^edit_publisher2/([0-9]+)/$', views.edit_publisher2,name="edit_pub"),
1 | <a href="{% url 'edit_pub' publisher.id %}">分组匹配编辑</a> |
命名空间模式
- 当app多了,urls中的别名也可能会出现重复
1 | # project/urls.py |
1 | # app02/urls.py |
1 | <a href="{% url 'car:car_home' %}">想买车点我</a> |
通过URL分组和反射 将方法三合一
1 | # models |
1 | # urls.py |
1 | import re |
1 | # 正则表达式的匹配参数: |