目录
一、反序列化类校验部分源码解析(了解)
反序列化校验,什么时候,开始执行校验(切入点)
python-视图类中的 ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False
入口:ser.is_valid() 是序列化类的对象,假设序列化类是BookSerializer---》我们在他的内部找is_valid---》找不到,找到父类的父类BaseSerializer中有is_valid :【raise_exception:先注意,它的作用就是替代视图层中的if判断,当我们的程序运行is_valid的结果时False的时候会直接抛出异常】
pythondef 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_validationpython
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
python# 我们可以发现源码中大量使用try和断言 # 关键字assert ,有什么作用? # 我断定你是xx,如果不是就抛异常 name = 'lqz' # if name == 'lqz': # print('对了') # else: # # print('错了') # raise Exception('名字不为lqz,不能继续走了') assert name=='lqz' # 断定是,如果不是,就抛异常 print('后续代码')
三、drf之请求
3.1 Request能够解析的前端传入的编码格式
需求:该接口只能接收json格式,不能接收其他格式
方式一:在继承自APIView及其子类的的视图类中配置(局部配置)
python# 总共有三个: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,他的使用当时也是类似我们配置文件中的注册,'
方式二:在配置文件中配置(影响所有,全局配置)
python-django有套默认配置,每个项目有个配置 -drf有套默认配置,每个项目也有个配置---》就在django的配置文件中 REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ # 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', # 'rest_framework.parsers.MultiPartParser', ], }
方式三:全局配了1个,某个视图类想要3个,怎么配?
python-只需要在视图类,配置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对象中的方法。
pythondef __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能够响应的编码格式
python# 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的源码属性或方法
python# 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
pythonrest_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[通用视图类]
pythonrest_framework.generics.GenericAPIView
继承自APIVIew
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
提供的关于序列化器使用的属性与方法
-
属性:
- serializer_class 指明视图使用的序列化器
-
方法:
-
get_serializer_class(self)
ps:通常不直接用,因为在get_serializer代码内部也运行了他
当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器类,默认返回
pythonserializer_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扩展类使用,是列表视图与详情视图获取数据的基础,默认返回
pythonqueryset
属性,可以重写,例如:def get_queryset(self): user = self.request.user return user.accounts.all()
-
get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
举例:
python# 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 视图类
pythonfrom .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 序列化类
python### 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 路由
pythonurlpatterns = [ path('admin/', admin.site.urls), path('books/', views.BookView.as_view()), path('books/<int:pk>/', views.BookDetailView.as_view()), ]
六、基于GenericAPIView+5个视图扩展类
GenericAPIView属性和方法介绍
python''' # 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 视图类(推导流程)
python### 咱们能不能想一种方式,通过继承,少些代码-----》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 序列化类
pythonclass 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 路由
pythonurlpatterns = [ 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方法会对数据进行过滤和分页。
源代码:
highlighter- pythonclass 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)
举例:
highlighter- haskellfrom 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错误。
源代码:
highlighter- pythonclass 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。
源代码:
highlighter- pythonclass 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)
举例:
highlighter- haskellclass 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错误。
源代码:
highlighter- pythonclass 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。
源代码:
highlighter- pythonclass 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接口,代码:
highlighter- python"""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的视图子类
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)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
7)RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
七、作业
1 基于APIView写5个接口
基于GenericAPIView
models.py
pythonfrom 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
pythonfrom 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
pythonfrom 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
pythonfrom 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
pythonfrom 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
pythonfrom 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
pythonfrom 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
pythonfrom 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 剩下两层
第一层(两个视图完成功能)
pythonclass PublishView(CreateAPIView): queryset = Book.objects.all() serializer_class = BookSerializer class BookDetailView(DestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializer
代码
models.py
pythonfrom 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
pythonfrom 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
pythonfrom 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
pythonfrom 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()), ]
标签:get,self,request,视图,序列化,class,serializer,drf From: https://www.cnblogs.com/xiao-fu-zi/p/17092617.html