Django框架简介
- Django框架的作用:简便、快速的开发数据库驱动的网站
- Django框架的特点:1.重量级框架 2.MVT设计模式
MVT设计模式
- 核心思想:分工,解耦
让不同代码块之间降低耦合,增强代码的可扩展性和可移植性 - 传统MVC模式
M(Model):主要封装对数据库层的访问,对数据库中的数据进行增、删、查、改操作
V(View):用于封装结果,生成页面展示的html内容
C(Controller):用于接收请求,处理业务逻辑,与Model和View交互,返回结果 - Django使用MVT模式
M(Model):负责与数据库交互,进行数据处理,与MVC中的M功能相同
V(View):用于接收请求,进行业务处理,返回应答,与MVC中的C功能相同
T(Template):负责封装构造要返回的html,与MVC中的V功能相同
Django的搭建
- 创建虚拟环境
mkvirtualenv 虚拟环境名 -p python3.6
python版本可按具体需求而定
- 往虚拟环境中安装Django包
pip install django==2.2.5
django版本可按需求而定,通常安装python版本对应的django版本
- 创建一个Django工程
django-admin startproject 工程名
此时可以用tree命令查看工程文件:
.
└── demo
├── demo
│ ├── init.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
其中:
__init__.py:项目初始化文件
settings.py:项目的整体配置文件
urls.py:项目的URL配置文件
wsgi.py:项目与WSGI兼容的Web服务器入口
manage.py:项目管理文件,用于管理项目
- 使用开发服务器运行项目
python manage.py runserver
服务器运行后,在浏览器中输入“127.0.0.1:8000”即可看到原始页面
- 创建子应用
python manage.py startapp 子应用名
这时候我们通过tree命令查看工程文件,新增了以下文件:
└── users
├── __init__
.py
├── admin.py
├── apps.py
├── models.py
├── migrations
│ └──__init__.py
├── tests.py
└── views.py
其中:
admin.py:与网站的后台管理站点配置相关
apps.py:用于配置当前子应用的相关信息
migrations:目录用于存放数据库迁移历史文件
model.py:用于保存数据库模型类
test.py:用于开发测试用例,编写单元测试
views.py:用于编写Web应用视图
创建出来的子应用需要在项目工程的settings.py
文件中进行配置才可以使用,我们需要在demo目录下的settings.py文件的INSTALLED_APPS中添加子应用模块:'users.apps.UsersConfig'
,注意各元素之间以逗号隔开
- 创建视图
在子应用模块的views.py文件中编写视图代码
from django.http import HttpResponse
def index(request):
pass
return HttpReponse("响应体")
- 创建子路由
1)在子应用模块中新建一个urls.py文件保存该应用的路由,该路由被称为子路由
2)在users/urls.py文件中定义子路由信息:
from django.conf.urls import re_path
from . import views
urlpatterns = [
re_path(r"^index/$", views.index),
]
3)在工程总路由demo/urls.py中添加数据:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path(r"users/", include("users.urls)),
]
"users/"代表子路由以/users/开头
使用include将子应用users里的路由文件包含到总路由中
- 关于demo/settings.py文件中的几个重要配置
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
获取到的 BASE_DIR 其实就是当前项目的根目录(绝对路径)DEBUG = True
设置是否为调试模式,创建工程后初始值为True,项目真正部署上线时要修改成False
作用:Django程序出现异常时,在前端显示详细的错误追踪信息。LANGUAGE_CODE = 'en-us' # 语言
TIME_ZONE = 'UTC' # 时区
路由要点
- url的构成
eg:http://127.0.0.1:80/users/index/?a=1&b=2&c=3#box
协议 :// 域名(ip):端口 / 路由 /?查询字符串 #锚点
- 路由定义位置
总路由:位于项目的同名文件夹下的urls.py文件中
子路由:位于每个子应用下面的urls.py文件中 - 路由解析顺序:先总后子,从上至下
- 路由设置的正则表达式要^开头$结尾,否则可能出现屏蔽效应
- 路由命名
from django.conf.urls import re_path
from . import views
app_name = 'user'
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
re_path(r'^say', views.say, name='say'),
]
- reverse 反解析
from django.urls import reverse # 注意导包路径
def index(request):
# 我们在index函数中获取say函数的路径
url = reverse('user:say')
print(url) # /users/say
# 或者获取本函数的路径:
url1 = reverse('user:index')
print(url1) # /users/index
return HttpResponse("hello the world!")
def say(request):
return HttpResponse('say')
反解析可以通过自己为路由取的名字反向得到其路径
请求
- QueryDict对象:Django中的一种特殊类型的字典,可以存储一对一、一对多类型的数据。这个对象一般涌来存储浏览器传递过来的参数。
- 获取QueryDict中的数据:
获取一个值:QueryDict.get(key) 获取所有值的最后一个
获取多个值:QueryDict.getlist(key) 获取key对应的所有值,以列表形式返回 - 前端传参的四种方式:
1)查询字符串传参:利用url中的?后面的查询字符串部分进行传参
可以通过request.GET属性获取,这个方法返回QueryDict对象
// 前端发送请求:
$.ajax({
url:'http://127.0.0.1:8000/reqresp/qs/?a=1&b=2&a=3',
type:'get',
dataType:'json'
})
.done(function(data){
console.log(data) // 打印: OK
})
.fail(function(error){
console.log(error)
})
# python 部分接收发送的参数并打印:
# 视图函数
def qs(request):
# 获取查询字符串参数
a = request.GET.get('a')
b = request.GET.get('b')
alist = request.GET.getlist('a')
print(a) # 3
print(b) # 2
print(alist) # ['1', '3']
# 返回响应对象
return HttpResponse('OK')
需要注意的是,查询字符串不区分请求方式,即使客户端发送的是POST请求也可以通过request.GET获取请求中的查询字符串数据
2)路径传参:把参数伪装成路径, 传递到后端
在定义路由 URL 时,可以使用正则表达式提取参数的方法从 URL 中获取请求参数,Django 会将提取的未命名参数按定义顺序传递到视图的传入参数中。
除了未命名参数,我们可以对参数进行命名,这样能保证参数传递不会乱
命名参数子路由:
re_path(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather),
对应的视图部分:
def weather(request, year, city):
'''定义weather函数, 接收路径参数'''
print('city=%s' % city)
print('year=%s' % year)
return HttpResponse('OK')
3)请求体传参
Django 默认开启了 CSRF 防护,会对上述请求方式进行 CSRF 防护验证,在测试时可以关闭 CSRF 防护机制,方法为在 settings.py 文件中注释掉 CSRF 中间件
(1) 表单类型传参
使用request.POST获取QueryDict类型表单参数
使用 QueryDict 的 get( ) 和 getlist( ) 函数, 获取数据
(2) 非表单类型传参
若前端传递的是 json 类型的数据, 可以通过 request.body 类获取
获取到的数据是 bytes 类型, 所以我们需要将其解码为 str 类型
bytes 转为 str 后, 可以调用 json.loads( ) 函数转化为dict类型
4)请求头传参
通过 request.META 属性获取请求对象的所有请求头信息,dict类型
需要注意的是,从 request.META 中获取数据时, key 值需要大写
响应
- HttpResponse
1)导入方式
from django.http import HttpResponse
2)定义形式
HttpResponse(content,content_type,status)
其中:
content:响应体
content_type:响应体数据类型
status:状态码
def demo_response(request):
str = '{"name": "python"}'
return HttpResponse(str, content_type="application/json", status=400)
3)向响应头添加自定义的键值对
response = HttpResponse()
response['name'] = 'Python'
4)HttpResponse的子类
使用HttpResponse子类可以免去设置状态码,但用前记得导入对应的包
HttpResponseRedirect 301
HttpResponsePermanentRedirect 302
HttpResponseNotModified 304
HttpResponseBadRequest 400
HttpResponseNotFound 404
HttpResponseForbidden 403
HttpResponseNotAllowed 405
HttpResponseGone 410
HttpResponseServerError 500
- JsonResponse
1)作用
(1)自动将数据转换为 json字符串
(2)自动设置响应头 Content-Type 为 application/json
2)使用方法
导包后直接调用即可
from django.http import JsonResponse
def demo_view(request):
dict = {
'city': 'shenzhen',
'skill': 'python'
}
return JsonResponse(dict)
- redirect 重定向
1)作用:实现页面跳转
2)使用方法redirect('想要跳转的路径')
from django.shortcuts import redirect
def view1(request):
return redirect('/xxx/xx/')
3)redirect可以与reverse搭配使用
def demo_view2(request):
url = reverse('user:index')
return redirect(url)
类视图
- 什么是类视图?
Django中,使用类来定义一个视图称为类视图,对应的,以函数定义视图称为函数视图 - 类视图的优点
1)代码可读性强
2)相对于函数视图具有更高的复用性:类视图可以通过多继承获得父类的功能 - 类视图的使用
from django.views import View
from django.http import HttpResponse
class NewView(View):
def get(self, request):
...
return HttpResponse("")
def post(self, request):
...
return HttpResponse("")
同时,在子路由中要添加如下格式代码:
re_path(r'^newview/$', views.NewView.as_view())
注意:与函数视图不同的是,要在类名之后增加as_view()函数,as_view()函数能够根据请求类型(get / post)自动调用类视图中的对应函数
- as_view()函数的底层实现
@classonlymethod
def as_view(cls, **initkwargs):
...
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
...
return view
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
实际上,在调用as_view()函数时,会调用其内部的view()函数,view()函数再调用dispatch()函数实现 函数分发 ,决定调用类视图中的哪个函数,而这一切都是自动进行的
- 类视图使用装饰器
# 装饰器:
def my_decorator(func):
def wrapper(request, *args, **kwargs):
print('请求路径%s' % request.path)
return func(request, *args, **kwargs)
return wrapper
# 类视图:
class NewView(View):
def get(self, request):
print('调用get方法')
return HttpResponse('demoview get')
def post(self, request):
print('调用post方法')
return HttpResponse('demoview post')
1)在子路由配置给函数增加装饰器(不推荐)
urlpatterns = [
re_path(r'^demo/$', my_decorate(NewView.as_view()))
]
这种装饰方法是间接给类视图的所有函数增加装饰器,既不利于代码的可读性又不灵活,不建议使用
2)在类视图中装饰
(1)类内装饰
from django.utils.decorators import method_decorator
class DemoView(View):
@method_decorator(my_decorator) # 为 get 方法添加装饰器
def get(self, request):
print('类视图中的 get 方法')
return HttpResponse('demoview get')
def post(self, request):
print('类视图中的 post 方法')
return HttpResponse('demoview post')
(2)类外装饰
# 为特定请求方法添加装饰器
@method_decorator(my_decorator, name='get')
class DemoView(View):
def get(self, request):
print('类视图中的 get 方法')
return HttpResponse('demoview get')
def post(self, request):
print('类视图中的 post 方法')
return HttpResponse('demoview post')
# 为全部请求方法添加装饰器
@method_decorator(my_decorator, name='dispatch')
class DemoView(View):
def get(self, request):
print('类视图中的 get 方法')
return HttpResponse('demoview get')
def post(self, request):
print('类视图中的 post 方法')
return HttpResponse('demoview post')
这种方法需要导入django自带的method_decorator() 装饰器,相较于在子路由装饰具有更好的可读性和灵活性,推荐使用
- 类视图Mixin扩展类
def my_decorator_1(func):
def wrapper(request, *args, **kwargs):
print('请求路径%s' % request.path)
return func(request, *args, **kwargs)
return wrapper
def my_decorator_2(func):
def wrapper(request, *args, **kwargs):
print('请求路径%s' % request.path)
return func(request, *args, **kwargs)
return wrapper
class FirstMixin(object):
""" FirstMixin 扩展类 """
@classmethod
def as_view(cls, *args, **kwargs):
view = super().as_view(*args, **kwargs)
view = my_decorator_1(view)
return view
class SecondMixin(object):
""" SecondMixin 扩展类 """
@classmethod
def as_view(cls, *args, **kwargs):
view = super().as_view(*args, **kwargs)
view = my_decorator_2(view)
return view
class NewView(FirstMixin, SecondMixin, View):
def get(self, request):
print('newview get')
return HttpResponse('newview get')
def post(self, request):
print('newview post')
return HttpResponse('newview post')
扩展类第一眼看上去好像很复杂,但本质上就是类的继承而已。
注意:1.扩展类需要继承自object
2.类视图调用时,需要把View类添加到最后
3.在Mixin扩展类中,一般会重写as_view()函数,在函数内添加过滤
4.一个类视图可以继承多个扩展类, 每个扩展类中都可以添加装饰器
中间件
- 什么是中间件?
1)Django的中间件是一个轻量级、底层的插件系统,可以介入请求和响应处理过程,修改Django的输入与输出
2)中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性
3)我们可以使用中间件在Django视图的不同阶段对输入或输出进行处理 - 中间件的定义方式
1)在子应用中新建一个 middleware.py 文件,按以下格式编写中间件函数
def middleware(request):
...
response = get_response(request)
...
return response
return middleware
2)在setting.py文件中添加注册中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# 添加中间件
'users.middleware.my_middleware',
]
- 多个中间件的执行顺序
在请求视图被处理前,中间件由上至下依次执行
在请求视图被处理后,中间件由下至上依次执行
模板
- 配置
1)在工程中创建模板目录templates
2)在settings.py文件中修改TEMPLATES里的APP_DIRS值
将'APP_DIRS': True
改为'DIRS': [os.path.join(BASE_DIR, 'templates')]
- 定义模板
在templates目录中新建一个模板文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ city }}</h1>
</body>
</html>
- 渲染模板
使用方式:render(request, '模板文件名称', 添加给模板的字典类型数据)
from django.shortcuts import render
def index(request):
context = {'city': '深圳'}
return render(request,'index.html',context)
Cookie
- 什么是Cookie?
Cookie是由服务端生成,保存在客户端的一种数据存储形式,内部以Key-Value形式存储。Value最大为4KB,Cookie保存的数据不安全,Cookie基于域名安全,不同域名的Cookie是不能互相访问的。 - Cookie的作用:用于保持前后端状态
- 设置Cookie
通过HttpResponse对象中的set_cookie方法来设置cookie
response = HttpResponse()
response.set_cookie(key, value, max_age)
其中:
key: cookie 中保存信息的名称
value: cookie 中保存信息时, 名称对应的值部分
max_age: cookie 中保存信息的有效期, 超过有效期, key-value 失效
其中 max_age 单位为秒, 默认为 None. 如果设置 None 值, 则关闭浏览器失效.
- 读取Cookie
通过HttpRequest对象的COOKIES属性来读取本次携带的cookie值
value = request.COOKIES.get('key')
Session
- 什么是Session?
Session 是一种会话控制方式。 由服务端创建,并且保存在服务端的数据存储形式。 内部以 key/value 键值对的形式存储。session 可以保持会话状态,可以存储敏感信息, 内容有些会被加密。一般生成 session 后, 会把 sessionid 传递给 cookie 保存,session 依赖 cookie。 - Session的作用
1)在服务器上保存用户状态信息, 以供前端页面访问
2)因为数据保存在服务器端, 所以可以保存敏感信息, 每次前端发送请求, 可以随时获取对应的信息,保持会话状态 - Session的特点
1)依赖 cookies
2)存储敏感、重要的信息
3)支持更多字节,存储在Redis中最大可存储512MB
4)Session 共享:Session利用独立部署的session服务器(集群)统一管理Session,服务器每次读写Session时,都访问Session服务器。 - Session的机制:
1)客户端向服务器发起请求,如果服务器需要记录该用户状态,就可以通过Session在服务端将该用户的唯一标识信息存储起来。
session_key:一个随机的唯一的不重复的字符串
session_data:用户的唯一标识信息(密文)
2)然后,服务端会向客户端浏览器颁发一个Cookie。
该Cookie中包含了Session存储数据时使用的那个session_key
该Cookie的具体形式为:‘sessionid’: ‘session_key’
3)当浏览器再次请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。
4)服务器提取该Cookie中的session_key,再使用它提取session_data。
5)最后使用session_data来辨认用户状态 - 设置Session
在服务端响应时,使用如下格式代码设置Session:
request.session['key'] = value
- 读取Session
request.session.get('key', 默认值)
- 操作Session
1)清除所有Session,在存储中删除value部分
request.session.clear()
2)清除Session数据,在存储中删除Session的整条数据
request.session.flush()
3)删除Session中的指定键及值,在存储中只删除某个键及对应的值
del request.session['key']
4)设置Session的有效期
request.session.set_expiry(value)
注意:
(1) 如果value是一个整数,session将在value秒没有活动后过期。
(2) 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
(3) 如果value为None,那么session有效期将采用系统默认值,默认为两周。可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。
- Session的存储位置
1)默认存储位置:在settings.py的DATABASES配置项指定的SQL数据库中
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
2)本地缓存
SESSION_ENGINE='django.contrib.sessions.backends.cache'
3)混合存储
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
4)Redis
要在Redis中存储Session,需要导入django-redis包
(1)导包
pip install django-redis
(2)配置
在settings.py文件中做如下配置:
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"