Web框架-Django
1、工程搭建
1. 命令Django-admin startproject 项目名
2. 项目目录:
3. 目录说明
4. 运行服务器
1 | python manage.py runserver ip:port |
5. 创建子应用
1 | python manage.py startapp 模块名 |
6. 注册安装应用:
- 将子应用下的 apps 下的配置文件添加到settings下的INSTALLED_APPS组里
1 | INSTALLED_APPS = [ |
7. 返回视图
- 使用 django.http 里的 HttpResponse 模块进行响应
8. 配置路由
- 在创建的子应用中添加子路由配置:创建 urls.py 在里面配置子路由列表 urlpatterns 只能叫urlpatterns才能被识别
1 | urlpatterns = [ |
2、配置文件
1. BASE_DIR
1 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
当前工程目录,Django会依此来定位工程内的相关文件,我们也可以使用该参数来构造文件路径
此路径为项目的最外层父目录
2. DEBUG
调试模式,创建工程后初始值为True,即默认工作在调试模式下
作用:
- 修改代码文件,程序自动重启
- Django出现异常时,向前端显示详细的错误追踪信息
- 非调试模式下返回Server Error (500)
3. 本地语言和时区
初始化的工程默认语言和时区为英语和UTC标准时区
1 | LANGUAGE_CODE = 'en-us' |
将语言和时区修改为中国大陆信息
1 | LANGUAGE_CODE = 'zh-hans' |
3、静态文件
为了提供静态文件,需要配置两个参数:
- STATICFILES_DIRS存放查找静态文件的目录
- STATIC_URL 访问静态文件的URL前缀
1. 可以手动创建一个静态文件夹
在最外层福目录下创建文件夹,然后再settings.py末尾进行配置
1 | STATICFILES_DIRS = [ |
注意
Django 仅在调试模式下(DEBUG=True)能对外提供静态文件。
当DEBUG=False工作在生产模式时,Django不再对外提供静态文件,需要是用collectstatic命令来收集静态文件并交由其他静态文件服务器来提供。
4、路由与反解析
1、路由
1. 路由定义位置
Django的主要路由信息定义在工程同名目录下的urls.py文件中,该文件是Django解析路由的入口。
每个子应用为了保持相对独立,可以在各个子应用中定义属于自己的urls.py来保存该应用的路由。然后用主路由文件包含各应用的子路由数据。
除了上述方式外,也可将工程的全部路由信息都定义在主路由文件中,子应用不再设置urls.py。
2. 路由解析顺序
Django在接收到一个请求时,从主路由文件中的urlpatterns列表中以由上至下的顺序查找对应路由规则,如果发现规则为include包含,则再进入被包含的urls中的urlpatterns列表由上至下进行查询。
值得关注的由上至下的顺序,有可能会使上面的路由屏蔽掉下面的路由,带来非预期结果。
1 | urlpatterns = [ |
即使访问sayhello/路径,预期应该进入sayhello视图执行,但实际优先查找到了say路由规则也与sayhello/路径匹配,实际进入了say视图执行。
需要注意定义路由的顺序,避免出现屏蔽效应。
2、路由命名与reverse反解析(逆向)
1. 路由命名
在定义路由的时候,可以为路由命名,方便查找特定视图的具体路径信息。
1)在使用include函数定义路由时,可以使用namespace参数定义路由的命名空间,如
1 | url( r'^users/ ' , include( 'users.urls ', namespace='users ' ) ), |
命名空间表示,凡是users.urls中定义的路由,均属于namespace指明的users名下。
2)在定义普通路由时,可以使用name参数指明路由的名字,如
1 | urlpatterns = [ |
2. reverse反解析
使用reverse函数,可以根据路由名称,返回具体的路径,如︰
1 | from django.core.urlresolvers import ifeverse # 注意导包路径 |
- 对于未指明namespace的,reverse(路由name)
- 对于指明namespace的,reverse(命名空间namespace:路由name)
5、获取请求体的参数
1. 查询字符串Query String
获取请求路径中的查询字符串参数(形如?k1=v1&k2=v2),可以通过request.GET属性获取,返回ueryDict对象。
- 获取单个参数:request.GET.get('k1')
- 获取多个参数:request.GET.getlist('k1')
查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET获取请求中的查询字符串数据。
2. 请求体
请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串,应区别对待。
可以发送请求体数据的请求方式有POST、PUT、PATCH、DELETE。
Django默认开启了CSRF防护,会对上述请求方式进行CSRF防护验证,在测试时可以关闭CSRF防护机制,方法为在settings.py文件中注释掉CSRF中间件'django.middleware.csrf.CsrfViewMiddleware'
3. 表单类型Form Data
前端发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象。
只要请求体的数据是表单类型,无论是哪种请求方式(POST、PUT、PATCH、DELETE),都是使用request.POST来获取请求体的表单数据。
4. 非表单类型Non-Form Data
非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性获取最原始的请求体数据,自己按照请求体格式(JSON、XML等)进行解析。request.body返回bytes类型。
例如要获取请求体中的如下JSON数据
1 | json_str = request.body |
6、请求Request
1. URL路径参数
在定义路由URL时,可以使用正则表达式提取参数的方法从URL中获取请求参数,Django会将提取的参数直接传递到视图的传入参数中。
- 未命名参数按定义顺序传递,如
1 | url(r'^weather/([a-z]+)/(\d{4})/$', views.weather), |
- 命名参数按名字传递
1 | url(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather), |
2. Django中的QueryDict对象
定义在django.http.QueryDict
HttpRequest对象的属性GET、POST都是QueryDict类型的对象与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
- 方法get(O:根据键获取值
如果一个键同时拥有多个值将获取最后一个值
如果键不存在则返回None值,可以设置默认值进行后续处理
1 | dict.get('键', 默认值) |
- 方法getlist():根据键获取值,值以列表返回,可以获取指定键的所有值
如果键不存在则返回空列表[],可以设置默认值进行后续处理
1 | dict.gitlst('键', 默认值) |
3. 查询字符串Query String
获取请求路径中的查询字符串参数(形如?k1=v1&k2=v2),可以通过request.GET属性获取,返回QueryDt对象。
1 | def qs(request): |
重要:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET获取请求中的查询字符串数据。
4. 请求体
请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串,应区别对待。
可以发送请求体数据的请求方式有POST、PUT、PATCH、DELETE。
4.1 表单类型Form Data
前端发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象。
7、响应Response
视图在接收请求并处理后,必须返回HttpResponse对象或子对象。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。
1. HttpResponse
可以使用django.http.HttpResponse来构造响应对象。
1 | Response(content=响应体,content_type=响应体数据类型,status=状态码) |
也可通过HttpResponse对象属性来设置响应体、响应体数据类型、状态码︰
- content:表示返回的内容。
- status_code:返回的HTTP响应状态码。
- content_type:指定返回数据的的MIME类型。
响应头可以直接将HttpResponse对象当做字典进行响应头键值对的设置:
1 | response = Response( ) |
2. HttpResponse子类
- HttpResponseRedirect 301
- HttpResponsePermanentRedirect 302
- HttpResponseNotModified 304
- HttpResponseBadRequest 400
- HttpResponseNotFound 404
- HttpResponseForbidden 403
- HttpResponseNotAllowed 405
- HttpResponseGone 410
- HttpResponseServerError 500
3. JsonResponse
若要返回json数据,可以使用JsonResponse来构造响应对象,作用:
- 帮助我们将数据转换为json字符串
- 设置响应头Content-Type为application/json
1 | from django.http import JsonResponse |
4. redirect重定向
1 | from django.shortcuts import redirect |
8、Cookie
Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的keylvalue保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器〈前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型记住用户名。
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用。
Cookie的特点
- Cookie以键值对的格式进行信息的存储。
- Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Cookie 信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息。
- 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
1. 设置cookie
可以通过HttpResponse对象中的set_cookie方法来设置cookie。
HttpResponse.set_cookie(cookie名,value=cookie值,max_age=cookie有效期)
- max_age 单位为秒,默认为None。如果是临时cookie,可将max_age设置为None。
2. 读取cookie
可以通过HttpRequest对象的COOKIES属性来读取本次请求携带的cookie值。request.COOKIES为字典 类型。
9、Session
广义 session机制 -> 会话,用于记录多次http请求之间的关系,关系就是状态数据,比如登录状态
狭义 session数据 -> 会话数据,记录的状态数据,比如登录之后记录的user_id
存放位置:数据库中、本地缓存(程序的运行内存中,全局变量)、文件、redis
1. 启用Session
Django项目默认启用Session。
可以在settings.py文件中查看,如图所示
如需禁用session,将上图中的session中间件注释掉即可。
2. 存储方式
在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。
1 数据库
存储在数据库中,如下设置可以写,可以不写,这是默认存储
1 | SESSION_ENGINE = 'django.contrib.session.backends.db' |
如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。
2 本地缓存
存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
1 | SESSION_ENGINE = 'django.contrib.session.backends.cache' |
3 混合存储
1 | SESSION_ENGINE = 'django.contrib.session.backends.cached_db' |
4 Redis
在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决。
1)安装扩展
1 | pip install django-redis |
2)配置
在settings.py文件中配置
1 | CACHES = { |
3. Session操作
通过HttpRequest对象的session属性进行会话的读写操作
1)以键值对的格式写session
1 | request.session['键'] = '值' |
2)根据键读取值
1 | request.session.get('键',默认值) |
3)清除所有session,在存储中删除值部分。
1 | request.session.clear() |
4)清除session数据,在存储中删除session的整条数据。
1 | request.session.flush() |
5)删除session中的指定键及值,在存储中只删除某个键及对应的值。
1 | del request.session['键'] |
6)设置session的有效期
1 | request.session.set_expiry(value) |
- 如果value是一个整数,session将在value秒没有活动后过期。
- 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
- 如果value为None,那么session有效期将采用系统默认值,默认为两周,可以通过在settings.py中设置sESSION_COOKIE_AGE来设置全局默认值。
10、类视图
1、类视图引入
以函数的方式定义的视图称为函数视图,函数视图便于理解。但是遇到一个视图对应的路径提供了多种不同HTTP请求方式的支持时,便需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳。
1 | def register(request): |
在Django中也可以使用类来定义一个视图,称为类视图。
使用类视图可以将视图对应的不同请求方式以类中的不同方法来区别定义。如下所示
1 | from django.views.generic import View |
类视图的好处
- 代码可读性好
- 类视图相对于函数视图有更高的复用性,如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可
2、类视图的使用
定义类视图需要继承自Django提供的父类View,可使用from django.views.generic import View或者from django.views.generic.base import View导入,定义方式如上所示。
配置路由时,使用类视图的as_view()方法来添加。
3、类视图原理
1 |
|
4、类视图使用装饰器
为类视图添加装饰器,可以使用三种方法
为了理解方便,我们先来定义一个为函数视图准备的装饰器(在设计装饰器时基本都以函数视图作为考虑的被装饰对象),及一个要被装饰的类视图。
1 | def my_decorator(func): |
1. 在URL配置中装饰
1 | urlpatterns = { |
此种方式最简单,但因装饰行为被放置到了url配置中,单看视图的时候无法知道此视图还被添加了装饰器,不利于代码的完整性,不建议使用。
此种方式会为类视图中的所有请求方法都加上装饰器行为(因为是在视图入口处,分发请求方式前)。
2. 在类视图中装饰
在类视图中使用为函数视图准备的装饰器时,不能直接添加装饰器,需要使用 method_decorator 将其转换为适用于类视图方法的装饰器。
1 | from django.utils.decorators import method_decorator |
method_decorator装饰器还支持使用name参数指明被装饰的方法
1 | # 为全部请求添加装饰器 |
为什么需要使用method_decorator???
为函数视图准备的装饰器,其被调用时,第一个参数用于接收 request 对象
1 | def my_decorator(func): |
而类视图中请求方法被调用时,传入的第一个参数不是request对象,而是self视图对象本身,第二个位置参数才是request对象
1 | class DemoView(View): |
所以如果直接将用于函数视图的装饰器装饰类视图方法,会导致参数传递出现问题。
method_decorator的作用是为函数视图装饰器补充第一个self参数,以适配类视图方法。
如果将装饰器本身改为可以适配类视图方法的,类似如下,则无需再使用method_decorator。
1 | def my_decorator(gfunc): |
3. 构造Mixin扩展类
使用面向对象多继承的特性
1 | class MyDecoratorMixin(object): |
使用Mixin扩展类,也会为类视图的所有请求方法都添加装饰行为。
11、中间件
Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。
我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预。
1、中间件的定义方法
定义一个中间件工厂函数,然后返回一个可以别调用的中间件。
中间件工厂函数需要接收一个可以调用的get_response对象。
返回的中间件也是一个可以被调用的对象,并且像视图一样需要接收一个request对象参数,返回一个response对象。
1 | def simple_middleware(get_response): |
在定义好中间件后,需要在settings.py文件中添加注册中间件
1 | MIDDLEWARE = [ |
2、多个中间件执行的顺序
- 在请求视图被处理前,中间件由上至下依次执行
- 在请求视图被处理后,中间件由下至上依次执行
12、数据库
1、数据库配置
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
1 | DATABASES = { |
1. 使用MySQL数据库需要安装驱动程序pymysql
2. 在Django的工程同名子目录的__init__.py文件中添加如下语句
1 | from pymysql import install_as_MySQLdb |
作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。
3. 修改DATABASES配置信息
1 | DATABASES = { |
4. 在MySQL中创建数据库
2、定义模型类
模型类被定义在”应用/models.py”文件中。
模型类必须继承自Model类,位于包django.db.models中。
1. 定义
创建应用,在models.py文件中定义模型类。
1 | from django.db import models |
1)数据库表名
模型类如果未指明表名,Django默认以小写app应用名_小写模型类名为数据库表名
可通过 db_table 指明数据库表名
2)关于主键
django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列。
默认创建的主键列属性为id,可以使用pk代替,pk全拼为primary key。
3)属性名设置
- 不能是python的保留关键字。
- 不允许使用连续的下划线,这是由django的查询方式决定的。
- 定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
1 | 属性 = models.字段类型(选项) |
4)字段类型
| 类型 | 说明 |
|---|---|
| AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 |
| BooleanField | 布尔字段,值为True或False |
| NullBooleanField | 支持Null、True、False三种值 |
| CharField | 字符串,参数max_length表示最大字符个数 |
| TextField | 大文本字段,一般超过4000个字符时使用 |
| IntegerField | 整数 |
| DecimalField | 十进制浮点数,参数max_digits表示总位数,参数decimal_places表示小数位数 |
| FloatField | 浮点数 |
| DateField | 日期,参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于”最后一次修改”的时间戳,它总是使用当前日期,默认为False;参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False;参数auto_now_add和auto_now是相互排斥的,组合将会发生错误 |
| TimeField | 时间,参数同DateField |
| DateTimeField | 日期时间,参数同DateField |
| FileField | 上传文件字段 |
| lmageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片 |
5)选项
| 选项 | 说明 |
|---|---|
| null | 如果为True,表示允许为空,默认值是False |
| blank | 如果为True,则该字段允许为空白,默认值是False |
| db_column | 字段的名称,如果未指定,则使用属性的名称 |
| db_index | 若值为True,则在表中会为此字段创建索引,默认值是False |
| default | 默认 |
| primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用 |
| unique | 如果为True,这个字段在表中必须有唯一值,默认值是False |
null是数据库范畴的概念,blank是表单验证范畴的
6)外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
- CASCADE级联,删除主表数据时连通一起删除外键表中数据
- PROTECT保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
- SET_NULL设置为NULL,仅在该字段null=True允许为null时可用
- SET_DEFAULT设置为默认值,仅在该字段设置了默认值时可用SET()设置为特定值或者调用特定方法
- DO_NOTHING不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常
2. 迁移
将模型文件同步到数据库中
1)生成迁移文件
1 | python manage.py makemigrations |
2)同步到数据库中
1 | python manage.py migrate |
3. 添加数据测试
补充
1. shell工具
Django的manage工具提供了shell命令,帮助我们配置好当前工程的运行环境(如连接好数据库等),以便可以直接在终端中执行测试python语句。
通过命令 python manage.py shell 进入shell
倒入模型类,方便使用
1 | from 应用名.mode import 类名 |
2. 查看MySQL数据库日志
查看mysql数据库日志可以查看对数据库的操作记录。mysql日志文件默认没有产生,需要做如下配置:
Linux系统操作
将 mysqld.cnf 里68,69行注释取消,重启mysql服务
将 general_log 设为 1 开启日志功能
3、操作
1.增加
1)model.save()
1 | object1 = Object1(属性一 = 值一, 属性二 = 值二,···) |
2)Object.objects.create()
1 | Object.objects.create( |
2. 查询
1. 基本查询
get 查询单一结果,如果不存在会抛出模型类 .DoesNotExist 异常。
all 查询多个结果。
count 查询结果数量。
2. 过滤查询
实现SQL中的where功能,包括
- filter 过滤出多个结果
- exclude 排除掉符合条件剩下的结果
- get 过滤单一结果
对于过滤条件的便用,上述三个方法相同,故仅以filter进行讲解
过滤条件的表达语法如下:
1 | 属性名称__比较运算符=值 |
1)相等
exact: 表示判等 例:
2)模糊查询
contains:是否包含 (如果要包含%无需转义,直接写即可。)
startswith、endswith : 以指定值开头或结尾。
3)空查询isnull : 是否为null。
4)范围查询in :是否包含在范围内。 (比较的值为列表[])
5)比较查询
- gt 大于(greater then)
- gte大于等于(greater then equal)
- lt 小于(less then)
- lte 小于等于(less then equal)
不等于的运算符,使用exclude()过滤器。
6)日期查询year、month、day、week_day、hour、minute、second:对日期时间表
3. F对象
用于比较不同属性
语法:F(属性名)
4. Q对象
1)多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字
2)如果需要实现逻辑或or的查询,需要使用Q()对象结合|运算符,Q对象被义在
3)Q对象可以使用&、|连接,&表示逻辑与,|表示逻辑或。
4)Q对象前可以使用~操作符,表示非not。
5. 聚合函数
使用aggregate()过滤器调用聚合函数。
使用count时一般不使用aggregate过滤器
6. 排序
使用order_by对结果进行排序
1 | Object.objects.all( ).order_by ( ' bread ' )#升序 |
7. 关联查询
由一到多的访问语法:
—对应的模型类对象.多对应的模型类名小写_set例:
1 | object1 = Object1.objects.get(id=1) |
由多到一的访问语法:
多对应的模型类对象.多对应的模型类中的关系类属性名
1 | object2 = Object2.objects.get(id=1) |
访问一对应的模型类关联对象的id语法:
多对应的模型类对象.关联类属性_id
1 | object2 = Object2.objects.get(id=1) |
关联过滤查询
由多模型类条件查询一模型类数据:
语法如下:
1 | 关联模型类名小写__属性名__条件运算符 = 值 |
注意:如果没有”__运算符”部分,表示等于。








