CBV源码分析、 APIView的基本使用、 APIView执行流程分析、Request对象源码分析、序列化类Serializer的使用、序列化类常用字段和字段参数
CBV源码分析
# 基于类的视图--->
-必须要继承它:from django.views import View
# drf的东西,都是写cbv,必须要继承View
流程分析
path('books/', views.BookViwe.as_view())
views.BookViwe.as_view()的执行结果,是函数内存地址---->view这个函数的内存地址
# 请求来了---》路由匹配成功----》会执行 这个函数---》view(request)
# view- ---》self.dispatch(request)
def view(request, *args, **kwargs):
return self.dispatch(request, *args, **kwargs)
# dispatch---》你是什么请求,就会执行视图类中请求名字的方法
def dispatch(self, request, *args, **kwargs):
# 请求方法变成小写字符串 ,如果是get请求,就是 'get'
# self.http_method_names 列表 ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
if request.method.lower() in self.http_method_names:
# 重点:反射,去对象中,根据字符串,取出方法或属性
# 'get'--->self是视图类的对象--》handler就是你写在视图类中的get方法
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# 执行get方法---》视图函数的get方法
return handler(request, *args, **kwargs)
APIView的基本使用
# 上一节分析了---》View的执行流程
# 如果使用了drf,以后写的都是cbv,但是都是继承drf提供的视图类,APIView
from rest_framework.views import APIView
# 以后写的cbv要继承 APIView 及其子类
########## drf是个app,需要注册 ##########
INSTALLED_APPS = [
...
'rest_framework' # 一定不要忘了注册
]
# 2个坑: app后不加逗号,使用三引号加注释
补充
django项目中app的作用---》django是一个大而全的框架---》内置了很多app--》帮咱们完成了很多事---》数据库迁移,多了很多表,不是写的
INSTALLED_APPS = [
'django.contrib.admin', # 后台管理,系统自带后台管理admin
'django.contrib.auth', # 权限管理-->生成6张表
'django.contrib.contenttypes',# 对所有app的表进行记录的
'django.contrib.sessions', # session功能-->django-session表--->app
'django.contrib.messages', # django消息框架--->flask的闪现
'django.contrib.staticfiles', # 静态资源
'app01.apps.App01Config',
'rest_framework', # 一定不要忘了注册
]
views视图类编写
class BookViwe(APIView):
def get(self,request):
# return HttpResponse('hello web') # 以后不要用django原生的响应了:四件套:render,HttpResponse,Redirect,JsonResponse
return Response('hello web') # drf提供的响应--》放字符串,字典,列表:HttpResponse+JsonResponse结合体
# 由于继承了APIView---》执行APIView的as_view---》执行APIView的dispatch---》内部执行变化了
APIView执行流程分析
流程分析
# path('books/', views.BookViwe.as_view())
# views.BookViwe.as_view()的执行结果,是函数内存地址----》view这个函数的内存地址
# 现在的as_view已经不是django原生View的as_view了----》面向对象中 属性查找顺序---》而是drf的APIView的as_view了
#### 路由写法没变----》执行发生了变化 ####
# 请求来了---》路由匹配成功----》会执行 这个函数---》view(request)
#### 派生方法:子类中重写父类中的方法或者新写方法 叫派生
### 派生类---》子类
def as_view(cls, **initkwargs): # as_view是django的View的派生方法
# 这个view就是原生django中View类的view,还是原来的view
view = super().as_view(**initkwargs)
# csrf_exempt--->去除了所有的csrf--->csrf中间件--->post提交数据,如果不注释--->协带csrf--->以后,无论中间件是否注释,都不需要带了
# csrf_exempt装饰器装饰视图函数--->本质跟csrf_exempt(view)一毛一样
# 它就是装饰器的本质:把被装饰的函数当做参数,传入装饰器函数,返回值赋值给被装饰的函数
return csrf_exempt(view)
重点
1 view还是原来的view
2 以后不用管csrf了
------------------------------------------------------
# dispatch---》已经不是django原生View的dispatch了,是drf的APIView的dispatch了---》查找顺序的问题
def dispatch(self, request, *args, **kwargs):
#1 包装了新的request对象-->以后视图类中用的request对象,就是新的request
request = self.initialize_request(request, *args, **kwargs)
try: # 捕获了异常
# 内部执行了三大认证:认证(登陆认证),频率(1分钟只能访问接口3次),权限(普通用户不能访问,超级用户才能访问)
self.initial(request, *args, **kwargs)
# 原来dispatch的代码,重写了一下---》执行视图函数
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
response = handler(request, *args, **kwargs) # 执行视图函数
except Exception as exc:
# 处理了异常,统一异常处理---》返回固定格式
response = self.handle_exception(exc)
# 包装了response对象,响应对象,浏览器看到好看的样子,postman只看到json
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
分析重点总结
-1 drf:包装了新的request对象(drf的Request的对象了),已经不是django的request对象了
# rest_framework.request.Request 以后新的request
# django.core.handlers.wsgi.WSGIRequest django原来的
-2 在执行视图函数之前,执行了三大认证
-3 处理了全局异常 ---》执行三大认证期间,执行视图函数期间,如果出了错,都能统一处理
-4 包装了响应对象
Request对象源码分析
# 以后视图类中使用的request对象,是rest_framework.request.Request的对象
源码
class Request:
#1 把老的request放到了新的request的_request属性了
# 新的request--》request._request 是老的
-__init__里面: self._request = request(这个request是老的)
# 2 以后新的request用起来跟原来一样用
# 取出原来老request的属性,以下方法取,麻烦
request._request.POST
request._request.GET
request._request.method
# 所以重写了__getattr__ 魔法方法,. 拦截 -->对象.属性如果属性不存在,触发这个方法执行
# 新的request.POST,新的request中没有POST,触发Request类的__getattr__
def __getattr__(self, attr):
try:
# 通过反射,去拿老request的属性或方法
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
# 3 新的request有个data方法,包装成了数据属性
-前端无论什么编码方式传得body体中的数据,都从request.data中取,当字典用即可
-原生djagno,如果是formdata,urlencoded是从POST中取,如果是json,从body中取出来自己转
# 4 新的request有个query_params方法,包装成了数据属性
-就是原来老的request的GET属性
# 5 上传文件,跟之前一样用,但是人家重写了
分析重点
-1 老的request是新的request._request
-2 跟原来一样用
-3 body提交的数据都从request.data中取
-4 请求地址中的数据都从request.query_params中取
序列化类Serializer的使用
# 序列化组件--->一个类,可以完成下面的事
1. 序列化,把模型对象(book,queryset)转换成字典,经过drf的response以后变成json字符串
2. 反序列化,把客户端发送过来的数据(前端json格式字符串),经过request.data以后变成字典,序列化器可以把字典转成模型,存到数据库
3. 反序列化,完成数据校验功能--->前端传入的数据,长短,是否是邮箱,手机号。。可以做校验
'''序列化的功能 表中数据,序列化后,以json格式返回给前端'''
基本实现
路由
path('books/', views.BookAPIView.as_view()),
视图类
from rest_framework.response import Response
from rest_framework.views import APIView
from app01 import models
from app01 import serializer
class BookAPIView(APIView):
def get(self, request):
# 去除所有图书的queryset对象
books = models.Book.objects.all()
# 借助于序列化类--->写一个序列化类
# 类实例化时:instance:要序列化的对象 many:True 多条
ser = serializer.BookSerializer(instance=books, many=True)
# ser.data 完成了序列化
print(ser.data) # 把queryset对象转成了字典,根基序列化中你写的字段转的
return Response(ser.data)
序列化类
新建py文件serializers
from rest_framework import serializers
class BookSerializer(serializers.Serializer): # 一定要继承Serializer
# 写要序列化的字段
name = serializers.CharField() # 字段类,跟models中一一对应
price = serializers.IntegerField() # 字段类,跟models中一一对应
publish = serializers.CharField() # 字段类,跟models中一一对应
# 如果不想把某个字段给前端,直接给它注释掉即可
# author = serializers.CharField() # 字段类,跟models中一一对应
models
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
publish = models.CharField(max_length=32)
author = models.CharField(max_length=32)
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
浏览器访问
postman访问
序列化类常用字段和字段参数
常用字段类型:
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol=’both’, unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
选项参数:
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
通用参数
参数名称 | 说明 |
---|---|
read_only(重点) |
表明该字段仅用于序列化输出,默认False |
write_only(重点) |
表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |