Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
本文将以下方面带大家全面了解Django框架,笔者使用的版本为1.10.
-
流程
- 基本配置
- 路由系统
- 视图view
- 模板
- Model
- 中间件
- Form
- 认证系统
- CSRF
- 分页
- Cookie
- Seesion
- 缓存
- 序列化
- 信号
- admin
一、 Django流程介绍
MVC是众所周知的模式,即:将应用程序分解成三个组成部分:model(模型),view(视图),和 controller(控制 器)。其中:
M——管理应用程序的状态(通常存储到数据库中),并约束改变状态的行为(或者叫做“业务规则”)。
C——接受外部用户的操作,根据操作访问模型获取数据,并调用“视图”显示这些数据。控制器是将“模型”和“视图”隔离,并成为二者之间的联系纽带。
V——负责把数据格式化后呈现给用户。
Django也是一个MVC框架。但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),称为 MTV模式:
M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。
T 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。
V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。
二、 Django 基本配置
1. 创建django程序
- 终端命令:django-admin startproject sitename (在当前目录下创建一个Django程序)
- IDE创建Django程序时,本质上都是自动执行上述命令
其他常用命令:
python manage.py runserver ip:port (启动服务器,默认ip和端口为http://127.0.0.1:8000/)
python manage.py startapp appname (新建 app)
python manage.py syncdb (同步数据库命令,Django 1.7及以上版本需要用以下的命令)
python manage.py makemigrations (显示并记录所有数据的改动)
python manage.py migrate (将改动更新到数据库)
python manage.py createsuperuser (创建超级管理员)
python manage.py dbshell (数据库命令行)
python manage.py (查看命令列表)
2. 程序目录
3. 配置文件
a、数据库
支持SQLite 3(默认)、PostgreSQL 、MySQL、Oracle数据库的操作
具体配置
Django框架对于开发者而言高度透明化,对于不同数据库的具体使用方法是一致的,改变数据库类型只需要变动上述配置即可。
想要了解更多请戳这里
b、静态文件添加
settings配置
三、 Django 路由系统
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。URL的加载是从配置文件中开始。
参数说明:
- 一个正则表达式字符串
- 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 可选的要传递给视图函数的默认参数(字典形式)
- 一个可选的name参数
1. 示例
1 2 3 4 5 6 7 8 9 10 |
|
说明:
- 要捕获从URL中的值,用括号括起来,会当参数传入 views 视图。
- 没有必要添加一个斜线,因为每个URL都有。例如,它
^articles
不是^/articles
。 - 在
'r'
前面的每个正则表达式字符串中是可选的,但建议。它告诉Python字符串是“原始” -没有什么字符串中应该进行转义。
请求示例:
- 一个请求
/articles/2005/03/
会匹配上面列表中的第三条. Django 会调用函数views.month_archive(request, '2005', '03')
. /articles/2005/3/
不会匹配上面列表中的任何条目, 因为第三条的月份需要二位数字./articles/2003/
会匹配上第一条而不是第二条,因为匹配是按照从上到下顺序而进行的, Django 会调用函数views.special_case_2003(request)
/articles/2003
不会匹配上面列表中的任何条目, 因为每个URL应该以 / 结尾./articles/2003/03/03/
会匹配上最后一条. Django 会调用函数views.article_detail(request, '2003', '03', '03')
.
2. 命名组(Named groups)
在上面的简单例子中,并没有使用正则表达式分组,在更高级的用法中,很有可能使用正则分组来匹配URL并且将分组值通过参数传递给view函数。
在Python的正则表达式中,分组的语法是 (?P<name>pattern)
, name表示分组名,pattern表示一些匹配正则.
这里是一个简单的小例子:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 |
|
For example:
- A request to
/articles/2005/03/
会调用函数views.month_archive(request, year='2005',month='03')
, 而不是views.month_archive(request, '2005', '03')
. - A request to
/articles/2003/03/03/
会调用函数views.article_detail(request, year='2003',month='03', day='03')
.
常见写法实例:
3. 二级路由(Including)
那如果映射 url 太多怎么办,全写一个在 urlpatterns 显得繁琐,so 二级路由应用而生
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
在上面这个例子中,如果请求url为 /credit/reports/
则会调用函数 credit_views.report()
.
使用二级路由也可以减少代码冗余,使代码更加简洁易懂
4. 添加额外的参数
URLconfs 有一个钩子可以让你加入一些额外的参数到view函数中.
1 2 3 4 5 6 |
|
在上面的例子中,如果一个请求为 /blog/2005/
, Django 将会调用函数l views.year_archive(request, year='2005',foo='bar')
.
需要注意的是,当你加上参数时,对应函数views.year_archive必须加上一个参数,参数名也必须命名为 foo,如下:
1 2 3 |
|
5. 别名的使用
1 |
|
url中还支持name参数的配置,如果配置了name属性,在模板的文件中就可以使用name值来代替相应的url值.
我们来看一个例子:
name的应用
6. 指定view的默认配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
在上述的例子中,两个 URL 模式指向同一个视图 views.page
但第一图案不捕获从 URL 任何东西。如果第一个模式匹配,该 page()
函数将使用它的默认参数 num
,"1"
。如果第二图案相匹配时, page()
将使用任何 num
值由正则表达式捕获。
四、 Django Views(视图函数)
http请求中产生两个核心对象:
http请求:HttpRequest对象
http响应:HttpResponse对象
1. HttpRequest对象
当请求一个页面时,Django 创建一个 HttpRequest
对象包含原数据的请求。然后 Django 加载适当的视图,通过 HttpRequest
作为视图函数的第一个参数。每个视图负责返回一个HttpResponse
目标。
HttpRequest对象属性
2. HttpResponse对象
对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。
在HttpResponse对象上扩展的常用方法:
- 页面渲染:render(推荐),render_to_response,
- 页面跳转:redirect
- locals: 可以直接将对应视图函数中所有的变量传给模板
值得注意的是对于页面渲染的方法中,render和render_to_response使用方法和功能类似,但是render功能更为强大,推荐使用
3. render()
render(request, template_name, context=None, content_type=None, status=None, using=None)[source]
结合给定的模板与一个给定的上下文,返回一个字典HttpResponse在渲染文本对象
所需的参数
template_name 一个模板的使用或模板序列名称全称。如果序列是给定的,存在于第一个模板将被使用。
可选参数
context 一组字典的值添加到模板中。默认情况下,这是一个空的字典。
content_type MIME类型用于生成文档。
status 为响应状态代码。默认值为200
using 这个名字一个模板引擎的使用将模板。
render示例
五、 模板
1. 模板的执行
模版的创建过程,对于模版,其实就是读取模版(其中嵌套着模版标签),然后将 Model 中获取的数据插入到模版中,最后将信息返回给用户。
示例
2. 模板语言
模板中也有自己的语言,该语言可以实现数据展示
-
- {{ item }}
- {% for item in item_list %} <a>{{ item }}</a> {% endfor %}
forloop.counter
forloop.first
forloop.last - {% if ordered_warranty %} {% else %} {% endif %}
- 母板:{% block title %}{% endblock %}
子板:{% extends "base.html" %}
{% block title %}{% endblock %} - 帮助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}
{{ name|lower }}
小知识点:在模板语言中字典数据类型的取值是通过dict.xxx而不是dict[xxx]
3. 自定义标签
因为在模板语言中不能够做运算等一些稍显复杂的操作,所以在Django中提供了两种自定制标签,一种是simple_tag,一种是filter。
simple_tag: 任意传递参数,但是不能用作布尔判断
filter: 最多只能传递二个参数,可以用作布尔判断
在这里着重介绍simple_tag类型,filter的实现类似
a、在app中创建templatetags模块
b、创建任意 .py 文件,如:xx.py
示例
c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% my_simple_time 1 2 3%} {% my_input 'id_username' 'hide'%}
e、在settings中配置当前app,不然django无法找到自定义的simple_tag
示例
更多见文档:https://docs.djangoproject.com/en/1.10/ref/templates/language/
六、 Model
Django提供了一个抽象层(“Model”)来构建和管理Web应用程序的数据。
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
关系对象映射(Object Relational Mapping,简称ORM)。
1. 创建表
a、基本结构
1 2 3 4 5 6 |
|
更多参数
更多字段
元信息
拓展知识
b、连表结构
- 一对多:models.ForeignKey(其他表)
- 多对多:models.ManyToManyField(其他表)
- 一对一:models.OneToOneField(其他表)
应用场景:
- 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。- 多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好- 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
字段以及参数
2. 操作表
a、基本操作
基本操作
b、进阶操作(了不起的双下划线)
利用双下划线将字段和对应的操作连接起来
进阶操作
c、其他操作
其他操作
d、连表操作(了不起的双下划线)
利用双下划线和 _set 将表之间的操作连接起来
表结构实例
一对一操作
一对多
多对多操作
扩展:
a、自定义上传
示例
b、Form上传文件实例
View Code
c、ajax上传文件实例
HTML
Form
Models
View
七、中间件(MiddleWare)
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。
与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类
中间件中可以定义五个方法,分别是:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response)
- process_exception(self, request, exception)
- process_response(self, request, response)
分析源码得知前二个方法是从前往后执行的,后三个方法是从后往前执行的
所以前两个方法是请求进来时要穿越的,而后三个方法是请求出去时要穿越的
一张图告诉你中间件的运行流程
自定义中间件
1、创建中间件类
1 2 3 4 5 6 7 8 9 10 11 12 |
|
2、注册中间件
1 2 3 4 5 6 7 8 9 10 |
|
八、 Form
django中的Form一般有两种功能:
- 输入html
- 验证用户输入
Form
示例
利用Form还可以自动生成前端的input标签:
form.py
views.py
form1.html
扩展:ModelForm
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义
ModelForm
九、 认证系统(auth)
auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组管理,并且可以和admin模块配合使用.
在INSTALLED_APPS中添加'django.contrib.auth'使用该APP, auth模块默认启用.
model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
新建用户
user = User.objects.create_user(username, email, password) user.save() # 不存储用户密码明文而是存储一个Hash值
认证用户
from django.contrib.auth import authenticate user = authenticate(username=username, password=password) # 认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None. # 该方法不检查is_active标志位.
修改密码
user.set_password(new_password) # 以下实例为先认证通过后才可以修改密码 user = auth.authenticate(username=username, password=old_password) if user is not None: user.set_password(new_password) user.save()
登录
from django.contrib.auth import login # login向session中添加SESSION_KEY, 便于对用户进行跟踪: 'login(request, user)' # login不进行认证,也不检查is_active标志位 # 实例 user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user)
退出登录
# logout会移除request中的user信息, 并刷新session from django.contrib.auth import logout def logout_view(request): logout(request)
只允许登录的用户访问
@login_required
修饰器修饰的view函数会先通过session key检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到login_url
指定的位置.
若未指定login_url参数, 则重定向到settings.LOGIN_URL
from django.contrib.auth.decorators import login_required @login_required(login_url='/accounts/login/') def userinfo(request): ... # settings 配置 LOGIN_URL = '/index/' # views @login_required def userinfo(request): ...
十、 跨站请求伪造(csrf)
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
在Django1.10中,为了防止BREACH攻击,对cookie-form类型的csrf做了一点改进,即在cookie和form中的token值是不相同的
应用
1、普通表单
1 2 3 4 5 |
|
2、Ajax
对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。
view.py
text.html
更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
十一、 分页
1. Django内置分页
views.py
Html
扩展内置分页:views.py
扩展内置分页:Html
2. 自定义分页
分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...)
3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
4、在数据表中根据起始位置取值,页面上输出数据
需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...)
3、设定显示多少页号
4、获取当前数据总条数
5、根据设定显示多少页号和数据总条数计算出,总页数
6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
7、在数据表中根据起始位置取值,页面上输出数据
8、输出分页html,如:[上一页][1][2][3][4][5][下一页]
分页实例
总结,分页时需要做三件事:
- 创建处理分页数据的类
- 根据分页数据获取数据
- 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]
十二、 Cookie
1. 获取Cookie:
1 2 3 4 5 6 |
|
2. 设置Cookie:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
1 2 |
|
十三、 Session
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存+数据库
- 加密cookie
1、数据库Session
View Code
2、缓存Session
View Code
3、文件Session
View Code
4、缓存+数据库Session
View Code
5、加密cookie Session
View Code
跟数据库的操作一样,在Django中不同缓存方式的使用方法是一致的,想要改变缓存的类型只需要改变上述相应配置即可。
扩展:Session用户验证(装饰器)
1 2 3 4 5 6 7 |
|
十四、 缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
和数据库类似,缓存的具体操作都是一样的,使用不同的方式只需要将配置改掉即可
1、配置
a、开发调试
View Code
b、内存
View Code
c、文件
View Code
d、数据库
View Code
e、Memcache缓存(python-memcached模块)
View Code
f、Memcache缓存(pylibmc模块)
View Code
2、应用
a. 全站使用
View Code
b. 单独视图缓存
View Code
c、局部视图使用
View Code
注:如果出现多个url匹配同一个view函数的情况,缓存机制会根据每一个不同的url做单独的缓存
更多:猛击这里
十五、 序列化
关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。
1. serializers
1 2 3 4 5 |
|
2. json.dumps
1 2 3 4 5 6 7 8 |
|
由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:
自定义示例
十六、 信号
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
1、Django内置信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
View Code
2、自定义信号
a. 定义并注册信号
1 2 3 4 5 6 7 8 9 |
|
b. 触发信号
1 2 3 |
|
由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。
更多:猛击这里
十七、admin
django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:
- 创建后台管理员
- 配置url
- 注册和配置django admin后台管理页面
注:不建议新手经常使用admin,会形成依赖,核心的是model模块的操作!
1、创建后台管理员
|
2、配置后台管理url(默认已配)
|
3、注册和配置django admin 后台管理页面
a、在admin中执行如下配置
View Code
b、设置数据表名称
View Code
c、打开表之后,设定默认显示,需要在model中作如下配置
View Code
d、为数据表添加搜索功能
View Code
e、添加快速过滤
View Code
更多:https://docs.djangoproject.com/en/1.11/ref/contrib/admin/