为何要配置解析模块
1
2
3
4
5
|
"""
1)drf给咱们经过了多种解析数据包方式的解析类
2)咱们能够经过配置来控制前台提交的哪些格式的数据后台在解析,哪些数据不解析
3)全局配置就是针对每个视图类,局部配置就是针对指定的视图来,让它们能够按照配置规则选择性解析数据
"""
|
源码入口
1
2
3
4
5
6
7
8
|
# APIView类的dispatch方法中
request
=
self
.initialize_request(request,
*
args,
*
*
kwargs)
# 点进去
# 获取解析类
parsers
=
self
.get_parsers(),
# 点进去
# 去类属性(局部配置) 或 配置文件(全局配置) 拿 parser_classes
return
[parser()
for
parser
in
self
.parser_classes]
|
1
2
3
4
5
6
7
8
|
REST_FRAMEWORK
=
{
# 全局解析类配置
'DEFAULT_PARSER_CLASSES'
: [
'rest_framework.parsers.JSONParser'
,
# json数据包
'rest_framework.parsers.FormParser'
,
# urlencoding数据包
'rest_framework.parsers.MultiPartParser'
# form-date数据包
],
}
|
局部配置:应用views.py的具体视图类
1
2
3
4
5
|
from
rest_framework.parsers
import
JSONParser
class
Book(APIView):
# 局部解析类配置,只要json类型的数据包才能被解析
parser_classes
=
[JSONParser]
pass
|
异常模块
为何要自定义异常模块
1
2
3
4
5
6
|
"""
1)全部通过drf的APIView视图类产生的异常,均可以提供异常处理方案
2)drf默认提供了异常处理方案(rest_framework.views.exception_handler),可是处理范围有限
3)drf提供的处理方案两种,处理了返回异常现象,没处理返回None(后续就是服务器抛异常给前台)
4)自定义异常的目的就是解决drf没有处理的异常,让前台获得合理的异常信息返回,后台记录异常具体信息
"""
|
源码分析
1
2
3
4
5
6
7
8
9
10
11
|
# 异常模块:APIView类的dispatch方法中
response
=
self
.handle_exception(exc)
# 点进去
# 获取处理异常的句柄(方法)
# 一层层看源码,走的是配置文件,拿到的是rest_framework.views的exception_handler
# 自定义:直接写exception_handler函数,在本身的配置文件配置EXCEPTION_HANDLER指向本身的
exception_handler
=
self
.get_exception_handler()
# 异常处理的结果
# 自定义异常就是提供exception_handler异常处理函数,处理的目的就是让response必定有值
response
=
exception_handler(exc, context)
|
如何使用:自定义exception_handler函数如何书写实现体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# 修改本身的配置文件setting.py
REST_FRAMEWORK
=
{
# 全局配置异常模块
'EXCEPTION_HANDLER'
:
'api.exception.exception_handler'
,
}
# 1)先将异常处理交给rest_framework.views的exception_handler去处理
# 2)判断处理的结果(返回值)response,有值表明drf已经处理了,None表明须要本身处理
# 自定义异常处理文件exception,在文件中书写exception_handler函数
from
rest_framework.views
import
exception_handler as drf_exception_handler
from
rest_framework.views
import
Response
from
rest_framework
import
status
def
exception_handler(exc, context):
# drf的exception_handler作基础处理
response
=
drf_exception_handler(exc, context)
# 为空,自定义二次处理
if
response
is
None
:
# print(exc)
# print(context)
print
(
'%s - %s - %s'
%
(context[
'view'
], context[
'request'
].method, exc))
return
Response({
'detail'
:
'服务器错误'
}, status
=
status.HTTP_500_INTERNAL_SERVER_ERROR, exception
=
True
)
return
response
|
响应模块
响应类构造器:rest_framework.response.Response
1
2
3
4
5
6
7
8
9
10
11
12
|
def
__init__(
self
, data
=
None
, status
=
None
,
template_name
=
None
, headers
=
None
,
exception
=
False
, content_type
=
None
):
"""
:param data: 响应数据
:param status: http响应状态码
:param template_name: drf也能够渲染页面,渲染的页面模板地址(不用了解)
:param headers: 响应头
:param exception: 是否异常了
:param content_type: 响应的数据格式(通常不用处理,响应头中带了,且默认是json)
"""
pass
|
使用:常规实例化响应对象
1
2
3
4
|
# status就是解释一堆 数字 网络状态码的模块
from
rest_framework
import
status就是解释一堆 数字 网络状态码的模块
# 通常状况下只须要返回数据,status和headers都有默认值
return
Response(data
=
{数据}, status
=
status.HTTP_200_OK, headers
=
{设置的响应头})
|
序列化组件:
知识点:Serializer(偏底层)、ModelSerializer(重点)、ListModelSerializer(辅助群改)
Serializer
序列化准备:
-
模型层:models.pypython
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class
User(models.Model):
SEX_CHOICES
=
[
[
0
,
'男'
],
[
1
,
'女'
],
]
name
=
models.CharField(max_length
=
64
)
pwd
=
models.CharField(max_length
=
32
)
phone
=
models.CharField(max_length
=
11
, null
=
True
, default
=
None
)
sex
=
models.IntegerField(choices
=
SEX_CHOICES, default
=
0
)
icon
=
models.ImageField(upload_to
=
'icon'
, default
=
'icon/default.jpg'
)
class
Meta:
db_table
=
'old_boy_user'
verbose_name
=
'用户'
verbose_name_plural
=
verbose_name
def
__str__(
self
):
return
'%s'
%
self
.name
|
-
后台管理层:admin.py数据库
1
2
3
4
|
from
django.contrib
import
admin
from
.
import
models
admin.site.register(models.User)
|
-
配置层:settings.pydjango
1
2
3
4
5
|
# 注册rest_framework
INSTALLED_APPS
=
[
# ...
'rest_framework'
,
]
|
# 配置数据库# media资源MEDIA_URL = '/media/' # 后期高级序列化类与视图类,会使用该配置MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # media资源路径# 国际化配置LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'USE_I18N = TrueUSE_L10N = TrueUSE_TZ = False
-
主路由:项目下urls.pyjson
1
2
3
4
5
6
|
urlpatterns
=
[
# ...
url(r
'^api/'
, include(
'api.urls'
)),
url(r
'^media/(?P<path>.*)'
, serve, {
'document_root'
: settings.MEDIA_ROOT}),
]
|
-
子路由:应用下urls.pyapi
1
2
3
4
|
urlpatterns
=
[
url(r
'^users/$'
, views.User.as_view()),
url(r
'^users/(?P<pk>.*)/$'
, views.User.as_view()),
]
|
序列化使用
-
序列化层:api/serializers.py安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
"""
1)设置须要返回给前台 那些model类有对应的 字段,不须要返回的就不用设置了
2)设置方法字段,字段名能够随意,字段值有 get_字段名 提供,来完成一些须要处理在返回的数据
"""
# 序列化组件 - 为每个model类经过一套序列化工具类
# 序列化组件的工做方式与django froms组件很是类似
from
rest_framework
import
serializers, exceptions
from
django.conf
import
settings
from
.
import
models
class
UserSerializer(serializers.Serializer):
name
=
serializers.CharField()
phone
=
serializers.CharField()
# 序列化提供给前台的字段个数由后台决定,能够少提供,
# 可是提供的数据库对应的字段,名字必定要与数据库字段相同
# sex = serializers.IntegerField()
# icon = serializers.ImageField()
# 自定义序列化属性
# 属性名随意,值由固定的命名规范方法提供:
# get_属性名(self, 参与序列化的model对象)
# 返回值就是自定义序列化属性的值
gender
=
serializers.SerializerMethodField()
def
get_gender(
self
, obj):
# choice类型的解释型值 get_字段_display() 来访问
return
obj.get_sex_display()
icon
=
serializers.SerializerMethodField()
def
get_icon(
self
, obj):
# settings.MEDIA_URL: 本身配置的 /media/,给后面高级序列化与视图类准备的
# obj.icon不能直接做为数据返回,由于内容虽然是字符串,可是类型是ImageFieldFile类型
return
'%s%s%s'
%
(r
'http://127.0.0.1:8000'
, settings.MEDIA_URL,
str
(obj.icon))
|
-
视图层服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
"""
1)从数据库中将要序列化给前台的model对象,或是对个model对象查询出来
user_obj = models.User.objects.get(pk=pk) 或者
user_obj_list = models.User.objects.all()
2)将对象交给序列化处理,产生序列化对象,若是序列化的是多个数据,要设置many=True
user_ser = serializers.UserSerializer(user_obj) 或者
user_ser = serializers.UserSerializer(user_obj_list, many=True)
3)序列化 对象.data 就是能够返回给前台的序列化数据
return Response({
'status': 0,
'msg': 0,
'results': user_ser.data
})
"""
class
User(APIView):
def
get(
self
, request,
*
args,
*
*
kwargs):
pk
=
kwargs.get(
'pk'
)
if
pk:
try
:
# 用户对象不能直接做为数据返回给前台
user_obj
=
models.User.objects.get(pk
=
pk)
# 序列化一下用户对象
user_ser
=
serializers.UserSerializer(user_obj)
# print(user_ser, type(user_ser))
return
Response({
'status'
:
0
,
'msg'
:
0
,
'results'
: user_ser.data
})
except
:
return
Response({
'status'
:
2
,
'msg'
:
'用户不存在'
,
})
else
:
# 用户对象列表(queryset)不能直接做为数据返回给前台
user_obj_list
=
models.User.objects.
all
()
# 序列化一下用户对象
user_ser_data
=
serializers.UserSerializer(user_obj_list, many
=
True
).data
return
Response({
'status'
:
0
,
'msg'
:
0
,
'results'
: user_ser_data
})
|
反序列化使用
-
反序列层:api/serializers.py网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
"""
1)设置必填与选填序列化字段,设置校验规则
2)为须要额外校验的字段提供局部钩子函数,若是该字段不入库,且不参与全局钩子校验,能够将值取出校验
3)为有联合关系的字段们提供全局钩子函数,若是某些字段不入库,能够将值取出校验
4)重写create方法,完成校验经过的数据入库工做,获得新增的对象
"""
class
UserDeserializer(serializers.Serializer):
# 1) 哪些自动必须反序列化
# 2) 字段都有哪些安全校验
# 3) 哪些字段须要额外提供校验
# 4) 哪些字段间存在联合校验
# 注:反序列化字段都是用来入库的,不会出现自定义方法属性,会出现能够设置校验规则的自定义属性(re_pwd)
name
=
serializers.CharField(
max_length
=
64
,
min_length
=
3
,
error_messages
=
{
'max_length'
:
'太长'
,
'min_length'
:
'过短'
}
)
pwd
=
serializers.CharField()
phone
=
serializers.CharField(required
=
False
)
sex
=
serializers.IntegerField(required
=
False
)
# 自定义有校验规则的反序列化字段
re_pwd
=
serializers.CharField(required
=
True
)
# 小结:
# name,pwd,re_pwd为必填字段
# phone,sex为选填字段
# 五个字段都必须提供完成的校验规则
# 局部钩子:validate_要校验的字段名(self, 当前要校验字段的值)
# 校验规则:校验经过返回原值,校验失败,抛出异常
def
validate_name(
self
, value):
if
'g'
in
value.lower():
# 名字中不能出现g
raise
exceptions.ValidationError(
'名字非法,是个鸡贼!'
)
return
value
# 全局钩子:validate(self, 系统与局部钩子校验经过的全部数据)
# 校验规则:校验经过返回原值,校验失败,抛出异常
def
validate(
self
, attrs):
pwd
=
attrs.get(
'pwd'
)
re_pwd
=
attrs.pop(
're_pwd'
)
if
pwd !
=
re_pwd:
raise
exceptions.ValidationError({
'pwd&re_pwd'
:
'两次密码不一致'
})
return
attrs
# 要完成新增,须要本身重写 create 方法
def
create(
self
, validated_data):
# 尽可能在全部校验规则完毕以后,数据能够直接入库
return
models.User.objects.create(
*
*
validated_data)
|
-
视图层函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
"""
1)book_ser = serializers.UserDeserializer(data=request_data) # 数据必须赋值data
2)book_ser.is_valid() # 结果为 经过 | 不经过
3)不经过返回 book_ser.errors 给前台,经过 book_ser.save() 获得新增的对象,再正常返回
"""
class
User(APIView):
# 只考虑单增
def
post(
self
, request,
*
args,
*
*
kwargs):
# 请求数据
request_data
=
request.data
# 数据是否合法(增长对象须要一个字典数据)
if
not
isinstance
(request_data,
dict
)
or
request_data
=
=
{}:
return
Response({
'status'
:
1
,
'msg'
:
'数据有误'
,
})
# 数据类型合法,但数据内容不必定合法,须要校验数据,校验(参与反序列化)的数据须要赋值给data
book_ser
=
serializers.UserDeserializer(data
=
request_data)
# 序列化对象调用is_valid()完成校验,校验失败的失败信息都会被存储在 序列化对象.errors
if
book_ser.is_valid():
# 校验经过,完成新增
book_obj
=
book_ser.save()
return
Response({
'status'
:
0
,
'msg'
:
'ok'
,
'results'
: serializers.UserSerializer(book_obj).data
})
else
:
# 校验失败
return
Response({
'status'
:
1
,
'msg'
: book_ser.errors,
})
|