一、项目装备、配置、定义模型类(参考Django学习笔记4-Django模型Model配置以及数据的增删改查)
1、配置setting.py里的ALLOWED_HOSTS = []
限制访问方式
# 允许以那个主机的形式访问后端
# 默认是127.0.0.1
# 如果你改变了允许方式,需要将运行的ip / 域名 添加进来
# 安全机制:只能以罗列的形式来访问
ALLOWED_HOSTS = ['192..168.220.149','127.0.0.1']
2、URLconf
1)settings.py中
指定url配置
ROOT_URLCONF = '项目.urls'
2)项目中urls.py
匹配成功后,包含到应用的urls.py
url(正则, include('应用.urls'))
3)应用中urls.py
匹配成功后,调用views.py对应的函数
url(正则, views.函数名)
4)提示
-
正则部分推荐使用 r,表示字符串不转义,这样在正则表达式中使用 \ 只写一个就可以
-
不能在开始加反斜杠,推荐在结束加反斜杠
正确:path/ 正确:path 错误:/path 错误:/path/
-
请求的url被看做是一个普通的python字符串,进行匹配时不包括域名、get或post参数
如请求地址如下: http://127.0.0.1:8000/18/?a=10 去掉域名和参数部分后,只剩下如下部分与正则匹配 18/
二、路由
1、路由命名与reverse反解析
1)路由命名: 在定义路由的时候,可以为路由命名,方便查找特定视图的具体路径信息。
- 在使用include函数定义路由时,可以使用
namespace
参数定义路由的命名空间
url(r'^',include('book.urls',namespace='book'))
① 命名空间表示,凡是book.urls中定义的路由,均属于namespace指明的book名下。
②命名空间的作用:避免不同应用中的路由使用了相同的名字发生冲突,使用命名空间区别开。
- 在定义普通路由时,可以使用name参数指明路由的名字,如
urlpatterns = [
url(r'^$',index),
# 匹配书籍列表信息的URL,调用对应的bookList视图
url(r'^booklist/$',bookList,name='index'),
url(r'^testproject/$',views.testproject,name='test'),
]
2)reverse反解析
使用reverse函数,可以根据路由名称,返回具体的路径,如:
from django.core.urlresolvers import reverse
#或者
from django.urls import reverse
def testproject(request):
return HttpResponse("OK")
# 定义视图:提供书籍列表信息
def bookList(request):
url = reverse('book:test')
print(url)
return HttpResponse('index')
- 对于未指明namespace的,reverse(路由name)
- 对于指明namespace的,reverse(命名空间namespace:路由name)
2、使用 PostMan 对请求进行测试
PostMan 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件,可以直接去对我们写出来的路由和视图函数进行调试,作为后端程序员是必须要知道的一个工具。
安装方式1:去 Chrome 商店直接搜索 PostMan 扩展程序进行安装
安装方式2:https://www.getpostman.com/官网下载桌面版
安装方式3:将已下载好的 PostMan 插件文件夹拖入到浏览器
打开 Chrome 的扩展程序页面,打开开发者模式选将插件文件夹拖入到浏览器(或者点击加载已解压的扩展程序选择文件夹)
使用 PostMan,打开之后,会弹出注册页面,选择下方的Skip this,go straight to the app进行程序
三、HttpRequest对象
利用Http协议向服务器传参的四种途径
- 提取URL的特定部分,如/weather/beijing/2018,可以在服务器端的路由中用正则表达式截取;
- 查询字符串(query string),形如key1=value1&key2=value2;
- 请求体(body)中发送的数据,比如表单数据、json、xml;
- 在http报文的头(header)中。
1、URL路径参数
(1)从URL中获取值,需要在正则表达式中使用分组,获取值分为两种方式
1)位置参数:参数的位置不能错
# 分组来获取正则中的数据,根据位置来获取url的参数
# 指定标识符
url(r'^(\d+)/(\d+)/$',detail),
def detail(request,category_id,book_id):
# 1/100
print(category_id,book_id)
return HttpResponse("detail!")
2)关键字参数:参数的位置可以变,跟关键字保持一致即可
利用正则表达式能够为数据取别名,指定标识
# 分组来获取正则中的数据,根据位置来获取url的参数
# 指定标识符
url(r'^(?P<category_id>\d+)/(?P<book_id>\d+)/$',detail),
注意:
两种参数的方式不要混合使用,在一个正则表达式中只能使用一种参数方式
2、Django中的Get和QueryDict对象
(1)request.GET查询字符串
http: // 127.0.0.1: 8000 / 1 / 100 /?username = Amen & password = 123 & username = cjb
以?作为一个分隔
?前边 表示 路由
?后边 表示 get方式传递的参数 称之为 查询字符串
?key=value&key=value…
我们以这种方式访问:
http: // 127.0.0.1: 8000 / 1 / 100 /?username = Amen & password = 123 & username = cjb
我们可以去获取Get查询的东西
query_params = request.GET
print(query_params)
这时我们可以在终端将获取的信息打印出来:<QueryDict: {‘username’: [‘Amen’, ‘cjb’], ‘password’: [‘123’]}>
(2)QueryDict 以普通的字典形式来获取 一键多值的是时候 只能获取最后的那一个值
1) 方法get():根据键获取值
如果一个键同时拥有多个值将获取最后一个值
如果键不存在则返回None值,可以设置默认值进行后续处理
#get('键',默认值)
username = query_params.get('username')
password = query_params.get('password')
print(username, password)
2)方法getlist():根据键获取值,值以列表返回,可以获取指定键的所有值
如果键不存在则返回空列表[],可以设置默认值进行后续处理
#getlist('键',默认值)
username = query_params.getlist('username')
password = query_params.get('password')
print(username, password)
3、请求体
- 请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串,应区别对待。
- 可以发送请求体数据的请求方式有POST、PUT、PATCH、DELETE。
- Django默认开启了CSRF防护,会对上述请求方式进行CSRF防护验证,在测试时可以关闭CSRF防护机制,方法为在settings.py文件中注释掉CSRF中间件,如:
(1)request.POST获取表单类型数据
1)通过Postman来向请求地址增加对象
2)request.POST获取请求对象
data = request.POST
print(data)
(2)获取非表单类型
说明
非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性获取最原始的请求体数据,自己按照请求体格式(JSON、XML等)进行解析。request.body返回bytes类型。
1)通过Postman来向请求地址增加对象
Json数据:
{
"username":"Amen",
"password":"123"
}
2)request.body获取请求对象
body = request.body.decode("utf8")
print(body)
3)json数据(字符串类型)转换成字典:json.loads
import json
body = request.body.decode("utf8")
# {
# "username": "Amen",
# "password": "123"
# }
# 将字符串转换成字典
data = json.loads(body)
# {'password': '123', 'username': 'Amen'}
print(data['username'],data['password'])
4、请求头
可以通过request.META
属性获取请求头headers中的数据,request.META为字典类型。
常见的请求头如:
CONTENT_LENGTH– The length of the request body (as a string).
CONTENT_TYPE– The MIME type of the request body.
HTTP_ACCEPT– Acceptable content types for the response.
HTTP_ACCEPT_ENCODING– Acceptable encodings for the response.
HTTP_ACCEPT_LANGUAGE– Acceptable languages for the response.
HTTP_HOST– The HTTP Host header sent by the client.
HTTP_REFERER– The referring page, if any.
HTTP_USER_AGENT– The client’s user-agent string.
QUERY_STRING– The query string, as a single (unparsed) string.
REMOTE_ADDR– The IP address of the client.
REMOTE_HOST– The hostname of the client.
REMOTE_USER– The user authenticated by the Web server, if any.
REQUEST_METHOD– A string such as"GET"or"POST".
SERVER_NAME– The hostname of the server.
SERVER_PORT– The port of the server (as a string).
具体使用如:
def get_headers(request):
print(request.META['CONTENT_TYPE'])
return HttpResponse('OK')
5、其他常用HttpRequest对象属性
-
method:一个字符串,表示请求使用的HTTP方法,常用值包括:‘GET’、‘POST’。
-
user:请求的用户对象。
-
path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
-
encoding:一个字符串,表示提交的数据的编码方式。
如果为None则表示使用浏览器的默认设置,一般为utf-8。 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
-
FILES:一个类似于字典的对象,包含所有的上传文件。
四、HttpResponse对象
视图在接收请求并处理后,必须返回HttpResponse对象或子对象。
HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。
1、HttpResponse
HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)
from django.http import HttpResponse
data = {'name'}
#content 传递字符串,不要传递对象,字典等数据
#statue HTTP status code must be an integer from 100 to 599.只能使用系统规定的
#content_type 是个MINI类型(语法形式: 大类/小类)
return HttpResponse(data,status=400,content_type = '' )
Django提供了一系列HttpResponse的子类,可以快速设置状态码
HttpResponseRedirect 301 HttpResponsePermanentRedirect 302 HttpResponseNotModified 304 HttpResponseBadRequest 400 HttpResponseNotFound 404 HttpResponseForbidden 403 HttpResponseNotAllowed 405 HttpResponseGone 410 HttpResponseServerError 500
2、JsonResponse
若要返回json数据,可以使用JsonResponse来构造响应对象
作用: 帮助我们将数据转换为json字符串;设置响应头Content-Type为application/json
from django.http import JsonResponse
data = {'name':'cjb'}
return JsonResponse(data)
3、跳转页面:redirect重定向
from django.shortcuts import redirect
return redirect('https://blog.csdn.net/weixin_41446786')
五、状态保持
- 浏览器请求服务器是无状态的。
- 无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
- 无状态原因:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
- 有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
- 实现状态保持主要有两种方式:
在客户端存储信息使用Cookie
在服务器端存储信息使用Session
1、Cookie
(1)概念
1)cookie流程(原理)
-
第一次请求过程
① 我们的浏览器第一次请求服务器的时候,不会携带任何cookie信息
② 服务器接收到请求之后,发现 请求中没有任何cookie信息
③ 服务器设置一个cookie.这个cookie设置在响应中
④ 我们的浏览器接收到这个相应之后,发现相应中有cookie信息,浏览器会将cookie信息保存起来 -
第二次及其之后的过程
⑤ 当我们的浏览器第二次及其之后的请求都会携带cookie信息
⑥ 我们的服务器接收到请求之后,会发现请求中携带的cookie信息,这样的话就认识是谁的请求了
2)Cookie的特点
- Cookie以键值对的格式进行信息的存储。
- Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息。
- 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
(2)设置Cookie:通过HttpResponse对象中的set_cookie方法来设置cookie。
HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)
说明:max_age单位为秒,默认为None 。如果是临时cookie,可将max_age设置为None
1)添加一个路由信息
url(r'^set_cookie/$',set_cookie),
2)设置cookie(第一次请求,还没有cookie信息的时候):
# cookie 的第一次请求
def set_cookie(request):
#1. 先判断有没有cookie信息
#request.COOKIES
# 先假设就是没有
#2.获取用户名
username=request.GET.get('username')
#3. 因为我们假设没有cookie信息,我们服务器就要设置cookie信息
response = HttpResponse('set_cookie')
# key,value
response.set_cookie('username',username)
#4.返回相应
return response
(3)读取cookie(第二次请求,客服端已经携带cookie信息):
1)添加一个路由信息
url(r'^get_cookie/$', get_cookie),
2)获取cookie(第二次请求,接收客服端cookie信息的): cookie.get(键)
def get_cookie(request):
# 1.服务器可以接收查看cookie信息
cookie = request.COOKIES
# cookie是一个字典
username = cookie.get('username')
#2. 得到的用户信息可以继续其他的业务逻辑
return HttpResponse('get_cookie')
(3)删除Cookie: delete_cookie
response.delete_cookie('Amen')
2、Session
(1)启用session:Django默认启用session,如果需要禁用直接注释该语句
(注:session 依赖于 cookie;如果浏览器禁用cookie,则session不能实现)
(2)session的存储方式:在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等
1)数据库存储,默认存储方式
数据库表:
表结构:键,值,过期时间。
2)本地缓存:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
3 )混合存储:优先从本机内存中存取,如果没有则从数据库中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
4)Redis:在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决。
django-redis 中文文档
①安装扩展 :pip install django-redis
②配置
在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'
注意:如果redis的ip地址不是本地回环127.0.0.1,而是其他地址,访问Django时,可能出现Redis连接错误,如下:
解决方法:修改redis的配置文件,添加特定ip地址。
打开redis的配置文件:sudo vim /etc/redis/redis.conf
在如下配置项进行修改(如要添加10.211.55.5地址)
重新启动redis服务:sudo service redis-server restart
(3)流程
-
第一次请求:
① 我们第一次请求的时候可以携带一些信息(用户名/密码) cookie中没有任何信息
② 当我们的服务器接收到这个请求之后,进行用户名和密码的验证,验证没有问题可以设置session
信息
③ 在设置session信息的同时(session信息保存在服务器端).服务器会在响应头中设置一个 sessionid 的cookie信息(由服务器自己设置的,不是我们设置的)
④ 客户端(浏览器)在接收到响应之后,会将cookie信息保存起来(保存 sessionid的信息) -
第二次及其之后的请求:
⑤ 第二次及其之后的请求都会携带 session id信息
⑥ 当服务器接收到这个请求之后,会获取到sessionid信息,然后进行验证,
验证成功,则可以获取 session信息(session信息保存在服务器端)
(4)原理(Http角度)
第一次请求:
① 第一次请求,在请求头中没有携带任何cookie信息
② 我们在设置session的时候,session会做2件事.
- 第一件: 将数据保存在数据库中
- 第二件: 设置一个cookie信息,这个cookie信息是以 sessionid为key value为 xxxxx
cookie肯定会以响应的形式在相应头中出现
第二次及其之后的:
③ 都会携带 cookie信息,特别是 sessionid
(5)Session操作:通过HttpRequest对象的session属性进行会话的读写操作。
1) 以键值对的格式写session:request.session['键']=值
添加视图
def set_session(request):
# 1.cookie中没有任何信息
print(request.COOKIES)
#2.对用户名和密码进行验证
# 假设认为 用户名和密码正确
user_id=6666
#3.设置session信息
# request.session 理解为字典
# 设置session的时候其实 session做了2件事
#第一件: 将数据保存在数据库中
#第二件: 设置一个 cookie信息,这个cookie信息是以 sessionid为key
request.session['user_id']=user_id
#4. 返回响应
return HttpResponse('set_session')
添加一个路由信息
url(r'^set_session/$', set_session),
同时我们查看服务器默认存储的数据表django_session表可以查到对应的sessionid
2)根据键读取值:request.session.get('键',默认值)
添加视图
def get_session(request):
#1. 请求都会携带 session id信息
print(request.COOKIES)
#2. 会获取到sessionid信息,然后进行验证,
# 验证成功,可以获取 session信息(
# request.session 字典
user_id=request.session['user_id']
user_id=request.session.get('user_id')
#3.返回响应
return HttpResponse('get_session')
添加路由
url(r'^get_session/$', get_session),
3)清除所有session,在存储中删除值部分:request.session.clear()
4)清除session数据,在存储中删除session的整条数据:request.session.flush()
5)删除session中的指定键及值,在存储中只删除某个键及对应的值:del request.session['键']
6)设置session的有效期:request.session.set_expiry(value)
- 如果value是一个整数,session将在value秒没有活动后过期。
- 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
- 如果value为None,那么session有效期将采用系统默认值, 默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。
六、类视图和中间模块
1、类视图:
目的:运用面向对象的方式达到在一个页面同时处理多个逻辑(比如get/post)
(1)类视图的使用:类视图可以将视图对应的不同请求方式以类中的不同方法来区别定义
注:类视图需要继承自Django提供的父类View,可使用
from django.views.generic importView 或者
from django.views.generic.base import View导入
在视图view.py中:
from django.views.generic import View
class CenterView(View):
def get(self,request):
"""处理GET请求,返回个人中心展示页面"""
return HttpResponse('个人中心展示')
def post(self,request):
"""处理POST请求,实现个人中心修改"""
return HttpResponse('个人中心修改')
在路由url中配置路由时,使用类视图的as_view()
方法来添加:
url(r'^center/$',CenterView.as_view()),
(2)类视图的原理
(3)类视图的多继承重写
多继承的顺序:MRO super方法决定了继承的父类查找顺序为从第一个父类开始查找开始查找
from django.views.generic import View
from django.contrib.auth.mixins import LoginRequiredMixin
class CenterView(LoginRequiredMixin,View):
def get(self,request):
return HttpResponse('个人中心展示')
def post(self,request):
return HttpResponse('个人中心修改')
2、中间件
Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。
我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预。
中间件文档
(1)中间件的定义方法
- 定义一个中间件工厂函数,然后返回一个可以被调用的中间件。
- 中间件工厂函数需要接收一个可以调用的get_response对象。
- 返回的中间件也是一个可以被调用的对象,并且像视图一样需要接收一个request对象参数,返回一个response对象。
def simple_middleware(get_response):
# 此处编写的代码仅在Django第一次配置和初始化的时候执行一次。
def middleware(request):
# 此处编写的代码会在每个请求处理视图前被调用。
response = get_response(request)
# 此处编写的代码会在每个请求处理视图之后被调用。
return response
return middleware
例如,在book应用中新建一个middleware.py文件,
def my_middleware(get_response):
print('init 被调用')
def middleware(request):
print('before request 被调用')
response = get_response(request)
print('after response 被调用')
return response
return middleware
定义好中间件后,需要在settings.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',
'book.middleware.my_middleware', # 添加中间件
]
定义一个视图进行测试
def middleware(request):
print('view 视图被调用')
return HttpResponse('OK')
注:Django运行在调试模式下,中间件init部分有可能被调用两次。
- 在请求视图被处理前,中间件由上至下依次执行
- 在请求视图被处理后,中间件由下至上依次执行
定义多一个中间件执行请求可以验证: