drf-day5——反序列化类校验部分源码分析、断言、drf请求、drf响应、视图组件及两个视图基类、基于GenericAPIView+5个视图扩展类
一、反序列化类校验部分源码解析(了解)
反序列化校验,什么时候,开始执行校验(切入点)
-视图类中的 ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False
入口:ser.is_valid() 是序列化类的对象,假设序列化类是BookSerializer---》我们在他的内部找is_valid---》找不到,找到父类的父类BaseSerializer中有is_valid :【raise_exception:先注意,它的作用就是替代视图层中的if判断,当我们的程序运行is_valid的结果时False的时候会直接抛出异常】
def is_valid(self, *, raise_exception=False):
if not hasattr(self, '_validated_data'):
try:
# self序列化类的对象,属性中没有_validated_data,一定会走这句【核心】
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
'上面的代码我们简单区分一下可以分成两块,断言部分可以不管,当没有_validated_data这个属性或方法的时候会对他进行异常捕获。另一部分就是添加errors的错误信息并报错。通过这里我们可以猜到,执行序列化功能的代码肯定就是异常捕获那里了,而他的代码中运行了一个run_validation,这就是我们要研究的目标'
# self._validated_data = self.run_validation(self.initial_data) 核心--》self序列化类的对象
-切记一定不要按住ctrl键点击,直接点会去Fields.py文件中的run_validation
-真正的执行顺序是,从下往上找,对象中找不到,再往父类上一层层找
-最终从Serializer类中找到了run_validation,而不是Fields.py文件中找到的run_validation
def run_validation(self, data=empty):
# 字段自己的,validates方法(就是执行字段中的约束条件,对他们进行校验)
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
# 局部钩子----【局部钩子】(ctrl点进来后我们可以发现他的代码中有反射,用getattr去找validate_开头的方法,回顾一下drf中的局部钩子,两者命名格式一样,因此这里就是局部钩子)
value = self.to_internal_value(data)
try:
self.run_validators(value)
# 全局钩子--》如果在BookSerializer中写了validate,优先走它,非常简单,ctril点进去我们可以看到他其实啥都没做就把数据返回出去了,但是当我们自定义后,就会现用我们定义的全局钩子进行校验
value = self.validate(value)
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
# 局部钩子 self.to_internal_value(data) ---》self是BookSerializer的对象,从根上找
def to_internal_value(self, data):
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
# fields写在序列化类中一个个字段类的对象,即我们常说的字段名称
for field in fields:
# self BookSerializer的对象,反射validate_name
validate_method = getattr(self, 'validate_' + field.field_name, None)
try:
# 在执行BookSerializer类中的validate_name方法,传入了要校验的数据
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
二、断言
详见博客:https://www.cnblogs.com/zhihuanzzh/p/16796885.html
# 我们可以发现源码中大量使用try和断言
# 关键字assert ,有什么作用?
# 我断定你是xx,如果不是就抛异常
name = 'lqz'
# if name == 'lqz':
# print('对了')
# else:
# # print('错了')
# raise Exception('名字不为lqz,不能继续走了')
assert name=='lqz' # 断定是,如果不是,就抛异常
print('后续代码')
三、drf之请求
3.1 Request能够解析的前端传入的编码格式
需求:该接口只能接收json格式,不能接收其他格式
方式一:在继承自APIView及其子类的的视图类中配置(局部配置)
# 总共有三个:from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser,]
'我们在APIView中可以看到一个属性叫做parser_classes,ctrl点击他后面的方法DEFAULT_PARSER_CLASSES,我们可以看到并不能直接点进来,但是这里我们可以去rest_frameword的配置文件中找,找到一个叫settings.py的文件就能在内部找到DEFAULT_PARSER_CLASSES,他的使用当时也是类似我们配置文件中的注册,'
方式二:在配置文件中配置(影响所有,全局配置)
-django有套默认配置,每个项目有个配置
-drf有套默认配置,每个项目也有个配置---》就在django的配置文件中
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
# 'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
方式三:全局配了1个,某个视图类想要3个,怎么配?
-只需要在视图类,配置3个即可
-因为:先从视图类自身找,找不到,去项目的drf配置中找,再找不到,去drf默认的配置找
3.2 Request类有哪些属性和方法(学过)
常用参数
- data
POST、PUT、PATCH请求方式解析后的数据。(原生django的PUT请求在request.POST中取不到。)
- query_params
与原生的GET一样。
- 其他的方法和原来的request使用方法一致:
底层原理:在Request实例化对象时,self._request = request,将原来的request对象给了Request的对象,又在Request类中定义了__getattr__魔法方法,当在视图函数中获取request对象的属性和方法时,找不到会触发魔法方法的执行,利用反射获取原来的request对象中的方法。
def __getattr__(self, attr):
"""
If an attribute does not exist on this instance, then we also attempt
to proxy it to the underlying HttpRequest object.
"""
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
Response类的实例化参数
data:列表或者字典,序列化成json字符串返回给前端
status:响应状态码,默认是200:from rest_framework.status import HTTP_200_OK
headers :响应头,以字典的形式返回给前端
content_type :响应的编码格式
template_name :指定模板
class Test(APIView):
def get(self, request):
return Response(data={}, status=status.HTTP_201_CREATED, headers={'name': 'jasper'})
四、drf之响应
4.1 Response能够响应的编码格式
# drf 是djagno的一个app,所以要注册,不注册的话不能用浏览器访问接口
# drf的响应,如果使用浏览器和postman访问同一个接口,返回格式是不一样的(浏览器会报错,postman返回数据)
-drf做了个判断,如果是浏览器,好看一些,如果是postman只要json数据
# 方式一:在视图类中写(局部配置)
-两个响应类---》找---》drf的配置文件中找--》两个类(也是在rest_framework的settings.py文件中)
-from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes=[JSONRenderer,]
# 方式二:在项目配置文件中写(全局配置)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
# 方式三:使用顺序(一般就用内置的即可)
优先使用视图类中的配置,其次使用项目配置文件中的配置,最后使用内置的
4.2 Resposne的源码属性或方法
# drf 的Response 源码分析
-from rest_framework.response import Response
-视图类的方法返回时,retrun Response ,走它的__init__,init中可以传什么参数
# Response init可以传的参数
def __init__(self,
data=None,
status=None,
template_name=None,
headers=None,
exception=False,
content_type=None)
-data:之前咱们写的ser.data 可以是字典或列表,字符串---》序列化后返回给前端---》前端在响应体中看到的就是这个
-status:http响应的状态码,默认是200,你可以改
-drf在status包下,把所有http响应状态码都写了一遍,常量
-from rest_framework.status import HTTP_200_OK
-Response('dddd',status=status.HTTP_200_OK)
-template_name:了解即可,修改响应模板的样子,BrowsableAPIRenderer定死的样子,后期公司可以自己定制
-headers:响应头,http响应的响应头
-考你,原生djagno,如何像响应头中加东西
# 四件套 render,redirect,HttpResponse,JsonResponse
obj = HttpResponse('dddd')
obj['xxc'] = 'yyc'
return obj
-content_type :响应编码格式,一般不动
# 重点:data,status,headers
五、视图组件介绍及两个视图基类
两个视图基类
APIView
rest_framework.views.APIView
APIView
是REST framework提供的所有视图的基类,继承自Django的View
父类。
APIView
与View
的不同之处在于:
- 传入到视图方法中的是REST framework的
Request
对象,而不是Django的HttpRequeset
对象; - 视图方法可以返回REST framework的
Response
对象,视图会为响应数据设置(render)符合前端要求的格式; - 任何
APIException
异常都会被捕获到,并且处理成合适的响应信息; - 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
支持定义的类属性
- authentication_classes 列表或元祖,身份认证类
- permissoin_classes 列表或元祖,权限检查类
- throttle_classes 列表或元祖,流量控制类
在APIView
中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。
GenericAPIView[通用视图类]
rest_framework.generics.GenericAPIView
继承自APIVIew
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
提供的关于序列化器使用的属性与方法
属性:
- serializer_class 指明视图使用的序列化器
方法:
get_serializer_class(self)
ps:通常不直接用,因为在get_serializer代码内部也运行了他
当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器类,默认返回
serializer_class
,可以重写,例如:def get_serializer_class(self):
if self.request.user.is_staff:
return FullAccountSerializer
return BasicAccountSerializer
get_serializer(self, *args, **kwargs)
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
- request 当前视图的请求对象
- view 当前请求的类视图对象
- format 当前请求期望返回的数据格式
提供的关于数据库查询的属性与方法
属性:
- queryset 指明使用的数据查询集
方法:
get_queryset(self)
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回
queryset
属性,可以重写,例如:def get_queryset(self):
user = self.request.user
return user.accounts.all()
get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
举例:
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer def get(self, request, pk):
book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
serializer = self.get_serializer(book)
return Response(serializer.data)
其他可以设置的属性
- pagination_class 指明分页控制类
- filter_backends 指明过滤控制后端
# drf 视图,视图类,学过APIView,drf的基类,drf提供的最顶层的类
# 两个视图基类
APIVIew
-类属性:
renderer_classes # 响应格式
parser_classes #能够解析的请求格式
authentication_classes#认证类
throttle_classes#频率类
permission_classes#权限类
-基于APIView+ModelSerializer+Resposne写5个接口
-详见代码
5.1 APIView+ModelSerializer+Resposne写5个接口
5.1.1 视图类
from .models import Book
from .serializer import BookSerializer
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
ser = BookSerializer(instance=books, many=True)
return Response(ser.data)
def post(self, request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
# 咱们现在只有ser序列化类的对象,但是咱们想要,新增的对象---》序列化成字典---》大前提,序列化类中的create方法一定要返回新增的对象
return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
class BookDetailView(APIView):
def get(self, request, pk):
books = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=books)
return Response(ser.data)
def put(self, request, pk):
books = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=books, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '删除成功'})
5.1.2 序列化类
### ModelSerializer的使用
class BookSerializer(serializers.ModelSerializer):
# 跟表有关联
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
5.5.3 路由
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
六、基于GenericAPIView+5个视图扩展类
GenericAPIView属性和方法介绍
'''
# GenericAPIView属性介绍
1 queryset:要序列化或反序列化的表模型数据
2 serializer_class:使用的序列化类
3 lookup_field :查询单条的路由分组分出来的字段名
4 filter_backends:过滤类的配置(了解)
5 pagination_class:分页类的配置(了解)
# 方法
1 get_queryset :获取要序列化的对象
2 get_object :获取单个对象
3 get_serializer :获取序列化类,跟它差不多的get_serializer_class,一般重写它,不调用它(get_serializer内部也调用了他)
4 filter_queryset :过滤有关系(了解)
'''
6.1 视图类(推导流程)
### 咱们能不能想一种方式,通过继承,少些代码-----》GenericAPIView---》继承了APIView,有很多新的属性和方法
# 以后咱们可以基于这个类,来写5个接口
# 5个接口的效果一样,但是咱们代码 可用性变高了
# GenericAPIView 属性和方法
'''
# GenericAPIView属性介绍
1 queryset:要序列化或反序列化的表模型数据
2 serializer_class:使用的序列化类
3 lookup_field :查询单条的路由分组分出来的字段名
4 filter_backends:过滤类的配置(了解)
5 pagination_class:分页类的配置(了解)
# 方法
1 get_queryset :获取要序列化的对象
2 get_object :获取单个对象
3 get_serializer :获取序列化类 ,跟它差不多的get_serializer_class,一般重写它,不调用它
4 filter_queryset :过滤有关系(了解)
'''
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
# objs = self.queryset #这里可以拿到,但是不要这么用,GenericAPIView提供了一个方法,
objs = self.get_queryset() # 好处,可以重写该方法,后期可扩展性高
# 取序列化类,不要使用self.serializer_class,而要使用方法get_serializer(从源码中看就是丰富了一下他)
ser = self.get_serializer(instance=objs, many=True) # 后期可以重写get_serializer_class,指定使用哪个序列化类来序列化
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
# 咱们现在只有ser序列化类的对象,但是咱们想要,新增的对象---》序列化成字典---》大前提,序列化类中的create方法一定要返回新增的对象
return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, pk):
obj = self.get_object() # 获取单条
ser = self.get_serializer(instance=obj)
return Response(ser.data)
def put(self, request, pk):
obj = self.get_object()
ser = self.get_serializer(instance=obj, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
self.get_object().delete()
return Response({'code': 100, 'msg': '删除成功'})
### 第三册层,如果我们写Pulish的5个接口,继承自GenericAPIView,跟Book的区别只有两个类属性,我们可以再封装
### 封装了5个视图扩展类---》5个接口 get所有,get一个,post新增,put修改,delete删除
# 5个视图扩展类,没有继承APIView及其子类,它不能单独使用,必须配合GenericAPIView一起用才行
# CreateModelMixin:新增,咱们封装---》在CreateModelMixin里面写个post,但是人家不是,人家写了create方法,代码就是post的代码
# DestroyModelMixin:删除 destroy方法
# RetrieveModelMixin:查单条 retrieve方法
# ListModelMixin:查所有 list 方法
# UpdateModelMixin:更新 updata方法
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
ListModelMixin
# 基于GenericAPIView+5个视图扩展类写接口
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
## 再继续封装 --->使用效果变成----》 自己封装 9个
# 9个---》5个+2个+
from rest_framework.generics import ListAPIView, CreateAPIView, ListCreateAPIView
from rest_framework.generics import DestroyAPIView, UpdateAPIView, RetrieveAPIView, RetrieveUpdateDestroyAPIView, \
RetrieveDestroyAPIView, RetrieveUpdateAPIView # 没有DestroyUpdateAPIView
class PublishView(CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView(DestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 5个接口,用同一个---》路由会有问题,有两个get---》写了个魔法类
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
6.2 序列化类
class BookSerializer(serializers.ModelSerializer):
# 跟表有关联
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
6.3 路由
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
6.4五个视图扩展类介绍
作用:
提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
1)ListModelMixin
列表视图扩展类,提供list(request, *args, **kwargs)
方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
# 过滤
queryset = self.filter_queryset(self.get_queryset())
# 分页
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
# 序列化
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
举例:
from rest_framework.mixins import ListModelMixin
class BookListView(ListModelMixin, GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request):
return self.list(request)
2)CreateModelMixin
创建视图扩展类,提供create(request, *args, **kwargs)
方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
源代码:
class CreateModelMixin(object):
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
# 获取序列化器
serializer = self.get_serializer(data=request.data)
# 验证
serializer.is_valid(raise_exception=True)
# 保存
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
3)RetrieveModelMixin
详情视图扩展类,提供retrieve(request, *args, **kwargs)
方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
class RetrieveModelMixin(object):
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
# 获取对象,会检查对象的权限
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance)
return Response(serializer.data)
举例:
class BookDetailView(RetrieveModelMixin, GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
return self.retrieve(request)
4)UpdateModelMixin
更新视图扩展类,提供update(request, *args, **kwargs)
方法,可以快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)
方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
class UpdateModelMixin(object):
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
5)DestroyModelMixin
删除视图扩展类,提供destroy(request, *args, **kwargs)
方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
class DestroyModelMixin(object):
"""
Destroy a model instance.
"""
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
使用GenericAPIView和视图扩展类,实现api接口,代码:
"""GenericAPIView结合视图扩展类实现api接口"""
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class Students2GenericAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):
# 本次视图类中要操作的数据[必填]
queryset = Student.objects.all()
# 本次视图类中要调用的默认序列化器[玄天]
serializer_class = StudentModelSerializer
def get(self, request):
"""获取多个学生信息"""
return self.list(request)
def post(self,request):
"""添加学生信息"""
return self.create(request)
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student2GenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
# 在使用GenericAPIView视图获取或操作单个数据时,视图方法中的代表主键的参数最好是pk
def get(self,request,pk):
"""获取一条数据"""
return self.retrieve(request,pk)
def put(self,request,pk):
"""更新一条数据"""
return self.update(request,pk)
def delete(self,request,pk):
"""删除一条数据"""
return self.destroy(request,pk)
6.5 GenericAPIView的视图子类
ps:可以点进GenericAPIView的源码看,总共九个
1)CreateAPIView
提供 post 方法
继承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供 get 方法
继承自:GenericAPIView、ListModelMixin
3)RetrieveAPIView
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin
4)DestoryAPIView
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin
5)UpdateAPIView
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
6)ListCreateAPIView
提供 get、post方法
继承自: GenericAPIView、ListModelMixin、CreateModelMixin
7)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
8)RetrieveDestroyAPIView
提供 get、delete方法
继承自: GenericAPIView、RetrieveModelMixin、DestroyModelMixin
9)RetrieveUpdateDestroyAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
七、作业
1 基于APIView写5个接口
基于GenericAPIView
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32, default='xx')
price = models.CharField(max_length=32)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) # 留住,还有很多
authors = models.ManyToManyField(to='Author')
def publish_detail(self):
return {'name': self.publish.name, 'addr': self.publish.addr}
def author_list(self):
l = []
for author in self.authors.all():
l.append({'name': author.name, 'phone': author.phone})
return l
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11)
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
serializer.py
from rest_framework import serializers
from .models import Book, Author, Publish
class BookSerializer(serializers.ModelSerializer):
# 跟表有关联
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
views.py
from django.shortcuts import render,redirect,HttpResponse
from rest_framework.generics import GenericAPIView
from .models import Book
from .serializer import BookSerializer
from rest_framework.response import Response
# Create your views here.
class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self,request):
objs = self.get_queryset()
ser = self.get_serializer(instance=objs, many=True)
return Response(ser.data)
def post(self,request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':10000,'msg':'增加成功', 'result':ser.data})
else:
return Response({'code':10001,'msg':ser.errors})
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self,request,pk):
objs = self.get_object()
ser = self.get_serializer(instance=objs)
return Response(ser.data)
def put(self,request,pk):
objs = self.get_object()
ser = self.get_serializer(data=request.data,instance=objs)
if ser.is_valid():
ser.save()
return Response({'code': 10000, 'msg': '修改成功', 'result': ser.data})
else:
return Response({'code': 10001, 'msg': ser.errors})
def delete(self,request,pk):
self.get_object().delete()
return Response({'code': 10000, 'msg': '删除成功'})
基于GenericAPIView+5个视图扩展类
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32, default='xx')
price = models.CharField(max_length=32)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) # 留住,还有很多
authors = models.ManyToManyField(to='Author')
def publish_detail(self):
return {'name': self.publish.name, 'addr': self.publish.addr}
def author_list(self):
l = []
for author in self.authors.all():
l.append({'name': author.name, 'phone': author.phone})
return l
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11)
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
serializer.py
from rest_framework import serializers
from .models import Book, Author, Publish
class BookSerializer(serializers.ModelSerializer):
# 跟表有关联
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
views.py
from django.shortcuts import render
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
ListModelMixin
from rest_framework.generics import GenericAPIView
from .models import Book, Publish, Author
from .serializer import BookSerializer
# Create your views here.
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class BookDetailView(GenericAPIView, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
2 剩下两层
第一层(两个视图完成功能)
class PublishView(CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView(DestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
代码
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32,default='xx')
price = models.CharField(max_length=32)
publish = models.ForeignKey(to='Puplish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def publish_detail(self):
return {'name':self.publish.name,'addr':self.publish.addr}
def author_list(self):
l = []
for author in self.authors.all():
l.append({'name':author.name,'phone':author.phone})
return l
class Puplish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=32)
urls.py
from django.shortcuts import render
from .models import Book, Puplish, Author
from rest_framework.generics import GenericAPIView, ListCreateAPIView, RetrieveUpdateDestroyAPIView
from .serializer import BookSerializer
from rest_framework.response import Response
# Create your views here.
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
serializer.py
from rest_framework import serializers
from .models import Book, Puplish, Author
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {
'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
views.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
第二层带5个接口(一个视图完成五个功能)
class PublishView(CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
代码
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def publish_detail(self):
return {'name':self.publish.name,'addr':self.publish.addr}
def author_list(self):
l = []
for author in self.authors.all():
l.append({'name':author.name,'phone':author.phone})
return l
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11)
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookDetailView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
serializer.py
from rest_framework import serializers
from .models import Book, Publish, Author
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {
'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
views.py
from django.shortcuts import render
from .models import Book,Publish,Author
from rest_framework.generics import RetrieveUpdateDestroyAPIView,CreateAPIView
from .serializer import BookSerializer
# Create your views here.
class BookDetailView(RetrieveUpdateDestroyAPIView,CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
drf-day5——反序列化类校验部分源码分析、断言、drf请求、drf响应、视图组件及两个视图基类、基于GenericAPIView+5个视图扩展类的更多相关文章
- Django框架之drf:5、反序列化器校验部分源码分析、断言、drf之请求与响应、视图组件介绍及两个视图基类、代码部分实战
Django框架之drf 目录 Django框架之drf 一.反序列化类校验部分源码解析 二.断言 三.drf之请求 1.Request能够解析的前端传入编码格式 2.Request类中的属性和方法 ...
- Vue.js 源码分析(二十八) 高级应用 transition组件 详解
transition组件可以给任何元素和组件添加进入/离开过渡,但只能给单个组件实行过渡效果(多个元素可以用transition-group组件,下一节再讲),调用该内置组件时,可以传入如下特性: n ...
- 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 百篇博客分析OpenHarmony源码 | v25.01
百篇博客系列篇.本篇为: v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- drf 认证校验及源码分析
认证校验 认证校验是十分重要的,如用户如果不登陆就不能访问某些接口. 再比如用户不登陆就不能够对一个接口做哪些操作. drf中认证的写法流程如下: 1.写一个类,继承BaseAuthenticatio ...
- Arrays工具类使用与源码分析(1)
Arrays工具类主要是方便数组操作的,学习好该类可以让我们在编程过程中轻松解决数组相关的问题,简化代码的开发. Arrays类有一个私有的构造函数,没有对外提供实例化的方法,因此无法实例化对象.因为 ...
- drf框架,restful接口规范,源码分析
复习 """ 1.vue如果控制html 在html中设置挂载点.导入vue.js环境.创建Vue对象与挂载点绑定 2.vue是渐进式js框架 3.vue指令 {{ }} ...
- drf的基本使用、APIView源码分析和CBV源码拓展
cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...
- Vue.js 源码分析(二十九) 高级应用 transition-group组件 详解
对于过度动画如果要同时渲染整个列表时,可以使用transition-group组件. transition-group组件的props和transition组件类似,不同点是transition-gr ...
- sentinel流控规则校验之源码分析
前言: 上节给大家把sentinel流控整个执行大致过了,但涉及到最核心的流控算法还没有讲,先提前说明一下 sentinel用的流控算法是令牌桶算法,参考了Guava的RateLimiter,有读过R ...
随机推荐
- day09-Tomcat01
Tomcat01 1.WEB开发介绍 WEB,在英文中WEB表示网/网络资源,它用于表示WEB服务器(主机)供浏览器访问的资源 WEB服务器(主机)上供外界访问的Web资源为: 静态web资源(如ht ...
- 通过jmeter连接人大金仓数据库
某项目用的人大金仓数据库,做性能测试,需要用jmeter来连接数据库处理一批数据.jmeter连接人大金仓,做个记录. 1. 概要 在"配置元件"中添加"JDBC Con ...
- perl静态变量
state操作符功能类似于C里面的static修饰符,state关键字将局部变量变得持久. state也是词法变量,所以只在定义该变量的词法作用域中有效,举个例子: #!/usr/bin/perl u ...
- 强软弱引用,ThreadLocal和内存泄漏
强引用 写法:Object obj=new Object() 引用强度:最强 只要被引用着,就不会被gc(垃圾回收)回收掉. 软引用 写法:SoftReference<String> sr ...
- [linux]非root账户 sudo cd 无法切换目录解决办法
在Centos上有个账户A(非root),有sudo权限(权限比较大),想要用 cd 命令切换到 B账号的 /home/B 下的目录,结果没作用 [liuzz ~]$ sudo cd /home/xi ...
- go如何编写命令行(cli)程序
创建一个命令行程序 问题 如何使用golang创建可以在命令行当中传递参数的程序?go如何带参数执行程序? 比如我们期望使用hello -version来查看hello程序的版本号码.或者输入hell ...
- Training: Get Sourced
原题链接:http://www.wechall.net/challenge/training/get_sourced/index.php 提示告诉我们答案就藏在这个界面中,使用View Sourcec ...
- Devexpress中gridControl设置一列不可以编辑
gridView1.Columns["列名"].OptionsColumn.AllowEdit = false;//设置列不可以编辑 记录一下. 大家如果有问题可以 Consol ...
- jmeter中下一接口依赖上一接口的参数,上一个接口存在分页时,如何在下一接口循环读取上一接口的数据?
问题背景: 工作中性能测试存在接口数据依赖,B接口依赖A接口的数据,希望提取到A接口的数据,传入到B接口,但是A接口存在分页的情况. 如何保证A接口返回的数据未知,且每次从A接口传给B接口的数据不重复 ...
- 云小课|云小课教您如何选择Redis实例类型
阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:购买Redis实例 ...