自定义只读
自定义只读:Model类中 @property def 字段(self): return "字段值"
models.py
class Book(BaseModel): name = models.CharField(max_length=64) price = models.DecimalField(max_digits=5, decimal_places=2, null=True) image = models.ImageField(upload_to='img', default='img/default.png') publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING) authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False) @property # @property字段默认就是read_only,且不允许修改 def publish_name(self): return self.publish.name
自定义只写
自定义只写:Serializer类中 字段 = serializers.字段类型(write_only=True)
serializers.py
class BookModelSerializer(serializers.ModelSerializer): class Meta: list_serializer_class = BookListSerializer model = models.Book fields = ['name', 'price', 'image', 'publish', 'authors', 'publish_name', 'author_list'] extra_kwargs = { 'publish': { 'write_only': True }
序列化覆盖字段
覆盖字段:Serializer类中,规则在()中规定,可以是只读、只写、可读可写任何形式 系统同名字段 = serializers.字段类型() # 如何覆盖外键字段 publish = serializers.PrimaryKeyRelatedField(read_only=True) # 只读 # publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all(), write_only=True) # 只写 # publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all()) # 可读可写 # publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all()) # authors = serializers.PrimaryKeyRelatedField(queryset=models.Author.objects.all(), many=True) class Meta: model = models.Book fields = ('name', 'publish', ) extra_kwargs = { 'publish': { # 系统原有的外键字段,要留给反序列化过程使用,序列化外键内容,用@property自定义 'write_only': True, },
二次封装Response
from rest_framework.response import Response class APIResponse(Response): def __init__(self, status=0, msg='ok', http_status=None, headers=None, exception=False, **kwargs): data = { 'status': status, 'msg': msg } # 在外界可以存值 if kwargs: data.update(kwargs) super().__init__(data=data, status=http_status, headers=headers, exception=exception)
数据库关系分析
""" 1)之间有关系的两个表,增删改操作会相互影响(效率低),查询操作就是正常的连表操作 2)之间有关系的两个表,断开关联,但所有数据保持与原来一致 每个表都可以单独操作,增删改操作效率极高,但是容易出现脏数据(开发中完全可以避免) 由于数据没有任何变化,所以查询的连表操作不会受到任何影响 3)Django的ORM支持断关联操作关系表,且所有的操作方式和没有断关联操作一致 """
断外键关联关系
有关联的表,如果直接存在关联关系(外键),增删改操作效率低(但是安全);删除外键(断关联),可以提高增删改操作效率,但是要手动处理数据安全问题(避免脏数据的参数) db_constraint=False eg: # 关系字段 brand = models.ForeignKey(to='Brand', related_name='Cars', db_constraint=False) sponsors = models.ManyToManyField(to="Sponsor", related_name="Cars", db_constraint=False)
ORM操作外键关系
外键位置:
""" 外键位置: 1)一对多:ForeignKey必须放在多的一方,书与出版社,外键应该放在书表 2)多对多:ManyToManyField放在任何一方都可以,因为会创建关系表,在关系表中用两个外键分别关联两个表 3)一对一:OneToOneField放在依赖的表,作者与作者详情,放在详情表,OneToOneField会被转换为 外键 + 唯一约束 """
外键操作:
ForeignKey可以设置:related_name, db_constraint, on_delete OneToOneField可以设置:related_name, db_constraint, on_delete ManyToManyField只能设置:related_name, db_constraint 不能设置on_delete的原因:不管是关联的A表,还是B表,数据修改,都会影响到关系表(默认级联), 如果想控制,只能自定义关系表,在关系表的两个外键分别设置on_delete
参数含义:
related_name:表之间反向访问的名字,默认是 表名小写|表名小写_set db_constraint:表之间的关联关系,默认为True,代表关联,设置False,可以提高增删改的效率,且不影响查等 on_delete:表之间级联更新,在django 1.x下默认是CASCADE(级联更新),在django 2.x下必须手动明确 DO_NOTHING(级联不更新)
案例:
""" 表关系: 作者没,作者详情一定没:CASCADE ***** 作者没,书还是该作者出的:DO_NOTHING 部门们,部门内的员工全部进入未分组部门:SET_DEFAULT (需要配合default属性使用) 部门们,部门内的员工部门外键字段设置为空:SET_NULL (需要配合null=True属性使用) ***** """
class Author(models.Model): name = models.CharField(max_length=64) class AuthorDetail(models.Model): phone = models.CharField(max_length=11) author = models.OneToOneField( to=Author, related_name='detail', db_constraint=False, on_delete=models.SET_NULL, null=True )
ORM四种关联关系
级联、不处理、置为默认值(配合默认值)、置空(配合可以为空)
基表
# 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的 # 抽出来的基类 class BaseModel(models.Model): name = models.CharField(max_length=64) is_delete = models.BooleanField(default=0) updated_time = models.DateTimeField(auto_now=True) class Meta: abstract = True # 必须完成该配置 class Car(BaseModel): pass # 其他的表继承了基类就有基类的属性了
序列化类其他配置(了解)
class AuthorModelSerializer(serializers.ModelSerializer): class Meta: model = models.Author # 不常用,将全部字段提供给外界 fields = '__all__' # ------------------------------------------------------------------ class AuthorModelSerializer(serializers.ModelSerializer): class Meta: model = models.Author # 不常用,非,排除指定字段的其他所有字段,不能自动包含 外键反向 字段 exclude = ['is_delete', 'updated_time'] # ------------------------------------------------------------------ class AuthorModelSerializer(serializers.ModelSerializer): class Meta: model = models.Author # 'detail', 'books' 是 外键(正向|反向) 字段 fields = ['name', 'detail', 'books'] # 不常用,自动深度,自动深度会显示外键关联表的所有字段 depth = 2 # 正向外键字段:就是外键的属性名 # 反向外键字段:就是外键属性设置的related_name
十大接口
BaseSerializer初始化方法
from rest_framework.serializers import BaseSerializer def __init__(self, instance=None, data=empty, **kwargs): self.instance = instance if data is not empty: self.initial_data = data self.partial = kwargs.pop('partial', False) self._context = kwargs.pop('context', {}) kwargs.pop('many', None) super().__init__(**kwargs) ''' instance:赋值对象的 data:赋值数据的 many:数据是单个还是多个 partial:在修改需求时使用,可以将所有校验字段required校验规则设置为False context:用于视图类和序列化类直接传参使用 '''
十大接口序列化总结
六个必备:单查、群查、单增、单删、单整体改(了解),单局部该 四个额外接口:群增、群删、群整体改、群局部改 # 常见使用 # 单查接口 get请求 UserModelSerializer(instance=user_obj) # 群查接口 get请求 UserModelSerializer(instance=user_query, many=True) # 单增接口,request.data是字典 post请求 UserModelSerializer(data=request.data) # 群增接口,request.data是列表 post请求 UserModelSerializer(data=request.data, many=True) # 单整体改接口,request.data是字典 put请求 UserModelSerializer(instance=user_obj, data=request.data) # 群整体改接口,request.data是列表,且可以分离出pks,转换成user_queryset put请求 UserModelSerializer(instance=user_queryset, data=request.data, many=True) # 单局部改接口,request.data是字典 patch请求 UserModelSerializer(instance=user_obj, data=request.data, partial=True) # 群局部改接口,request.data是列表,且可以分离出pks,转换成user_queryset patch请求 UserModelSerializer(instance=user_queryset, data=request.data, partial=True, many=True) # 删接口,用不到序列化类 delete请求 models.Car.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
单查群查
判断有无pk
class CarAPIView(APIView): def get(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: # 单查 try: obj = models.Car.objects.get(pk=pk) serializer = serializers.CarModelSerializer(obj) return APIResponse(result=serializer.data) except: return APIResponse(status=1, msg='pk error', http_status=status.HTTP_400_BAD_REQUEST, exception=True) else: # 群查 queryset = models.Car.objects.all() serializer = serializers.CarModelSerializer(queryset, many=True) return APIResponse(results=serializer.data)
单增群增
判断数据类型是否为列表
def post(self, request, *args, **kwargs): # 单增 if not isinstance(request.data, list): # 单增 serializer = serializers.CarModelSerializer(data=request.data) serializer.is_valid(raise_exception=True) # 如果校验失败,直接抛异常,返回给前台 car_obj = serializer.save() return APIResponse( result=serializers.CarModelSerializer(car_obj).data, status=status.HTTP_201_CREATED ) else: # 群增 serializer = serializers.CarModelSerializer(data=request.data,many=True) serializer.is_valid(raise_exception=True) # 如果校验失败,直接抛异常,返回给前台 objs = serializer.save() return APIResponse(result=serializers.CarModelSerializer(objs, many=True).data, http_status=201)
单删群删
判断前端传过来的数据:是url参数就是单删,是data数据就是群删
只是更改了表示是否删除的字段
# 单删群删 """ 单删:接口:/books/(pk)/ 群删:接口:/books/ 数据:[pk1, ..., pkn] """ def delete(self,request, *args,**kwargs): pk = kwargs.get('pk') if pk: pks = [pk] # [1] 单删 else: pks = request.data # [2,3,4] 群删 try: rows = models.Car.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True) except: return APIResponse(1, '数据有误') if rows: return APIResponse(0, '删除成功') return APIResponse(2, '删除失败')
单整体改/群整体改
# 单整体改群整体改 """ 单整体改:接口:/books/(pk)/ 数据:dict 群整体改:接口:/books/ 数据:[{pk1, ...}, ..., {pkn, ...}] | {pks: [pk1, ..., pkn], data: [{}, ..., {}]} """ def put(self,request, *args, **kwargs): pk = kwargs.get('pk') if pk: # 单 try: instance = models.Car.objects.get(is_delete=False, pk=pk) except: return APIResponse(1,'pk error', http_status=400) serializer = serializers.CarModelSerializer(instance=instance, data=request.data) serializer.is_valid(raise_exception=True) obj = serializer.save() # 返回的是受影响的对象 return APIResponse(result=serializers.CarModelSerializer(obj).data) else: # 群 pks = [] try: for dic in request.data: pks.append(dic.pop('pk')) objs = models.Car.objects.filter(is_delete=False, pk__in=pks) # 筛选 __in(或),双下线方法 assert len(objs) == len(request.data) # 两个列表长度必须一致 断言方法 except: return APIResponse(1, '数据有误', http_status=400) serializer = serializers.CarModelSerializer(instance=objs, data=request.data, many=True) serializer.is_valid(raise_exception=True) objs = serializer.save() return APIResponse(result=serializers.CarModelSerializer(objs, many=True).data)
单局部改/群局部改
# 单局部改群局部改 """ 单局部改:接口:/books/(pk)/ 数据:dict 群局部改:接口:/books/ 数据:[{pk1, ...}, ..., {pkn, ...}] | {pks: [pk1, ..., pkn], data: [{}, ..., {}]} """ def patch(self,request, *args, **kwargs): pk = kwargs.get('pk') if pk: # 单 try: instance = models.Car.objects.get(is_delete=False, pk=pk) except: return APIResponse(1, 'pk error', http_status=400) # partial=True就是将所有反序列化字段的 required 设置为 False(提供就校验,不提供不校验) serializer = serializers.CarModelSerializer( instance=instance, data=request.data, partial=True ) serializer.is_valid(raise_exception=True) obj = serializer.save() return APIResponse(result=serializers.CarModelSerializer(obj).data) else: pks = [] try: for dic in request.data: pks.append(dic.get('pk')) objs = models.Car.objects.filter(is_delete=False, pk__in=pks) assert len(objs) == len(request.data) except: return APIResponse(1, '数据有误', http_status=400) serializer = serializers.CarModelSerializer( instance=objs, data=request.data, many=True, partial=True, ) serializer.is_valid(raise_exception=True) objs = serializer.save() return APIResponse(result=serializers.CarModelSerializer(objs, many=True).data)
群增群改配置
serializers.py:
# 群增群改辅助类(了解) class BookListSerializer(serializers.ListSerializer): """ 1)create群增方法不需要重新 2)update群改方法需要重写,且需要和views中处理request.data的逻辑配套使用 3)self.child就代表该ListSerializer类绑定的ModelSerializer类 BookListSerializer的self.child就是BookModelSerializer """ # 重写update方法 def update(self, queryset, validated_data_list): return [ self.child.update(queryset[index], validated_data) for index, validated_data in enumerate(validated_data_list) ] class CarModelSerializer(serializers.ModelSerializer): class Meta: # 配置自定义群增群改序列化类 list_serializer_class = BookListSerializer
十大接口小结
""" 1)初始化序列化类,设置partial=True可以将所有反序列化字段的 required 设置为 False(提供就校验,不提供不校验),可以运用在局部修改接口 2)初始化序列化类,设置context={...},在序列化类操作self.context,实现视图类和序列化类数据互通 3)只有要完成资源的群改这种特殊需求时,才需要自定义ListSerializer绑定给自定义的ModelSerializer,重写update方法,来完成需求 """
字段提供就校验,不提供拉到
实现单局部该/群局部改
'required':False # partial=True就是将所有反序列化字段的 required 设置为 False(提供就校验,不提供不校验)
DjangoORM内置优化机制:一次最多查21条数据
queryset = models.Book.objects.filter(is_delete=False).all()
models.py
from django.db import models # 抽出来的基类 class BaseModel(models.Model): name = models.CharField(max_length=64) is_delete = models.BooleanField(default=0) updated_time = models.DateTimeField(auto_now=True) class Meta: abstract = True class Car(BaseModel): price = models.DecimalField(max_digits=9, decimal_places=2) # 关系字段 brand = models.ForeignKey(to='Brand', related_name='Cars', db_constraint=False) sponsors = models.ManyToManyField(to="Sponsor", related_name="Cars", db_constraint=False) class Meta: verbose_name_plural = '汽车表' def __str__(self): return self.name def brand_(self): return self.brand.name # 多对多跨表查询 def sponsors_(self): temp_sponsor_list = [] for sponsor in self.sponsors.all(): sponsor_dic = {"name": sponsor.name} try: sponsor_dic['电话'] = sponsor.detail.phone except: sponsor_dic['电话'] = '' temp_sponsor_list.append(sponsor_dic) return temp_sponsor_list class Brand(BaseModel): class Meta: verbose_name_plural = '品牌表' def __str__(self): return self.name # 一对多跨表查询 def car_list(self): temp_car_list = [] for car_obj in self.Cars.all(): car_dic = { "name": car_obj.name } try: car_dic['price'] = car_obj.price except: car_dic['price'] = '' temp_car_list.append(car_dic) return temp_car_list class Sponsor(BaseModel): class Meta: verbose_name_plural = '赞助商表' def __str__(self): return self.name class SponsorDetail(models.Model): class Meta: verbose_name_plural = '赞助商详情表' phone = models.CharField(max_length=11) is_delete = models.BooleanField(default=1) updated_time = models.DateTimeField(auto_now=True) sponsor = models.OneToOneField(to="Sponsor", related_name="detail", db_constraint=False)
response.py
from rest_framework.response import Response class APIResponse(Response): def __init__(self, status=0, msg='ok', http_status=None, headers=None, exception=False, **kwargs): data = { 'status': status, 'msg': msg } # 在外界可以存值 if kwargs: data.update(kwargs) super().__init__(data=data, status=http_status, headers=headers, exception=exception)
serializers.py
from rest_framework import serializers from rest_framework import exceptions from . import models # 群增群改辅助类(了解) class BookListSerializer(serializers.ListSerializer): """ 1)create群增方法不需要重新 2)update群改方法需要重写,且需要和views中处理request.data的逻辑配套使用 3)self.child就代表该ListSerializer类绑定的ModelSerializer类 BookListSerializer的self.child就是BookModelSerializer """ # 重写update方法 def update(self, queryset, validated_data_list): return [ self.child.update(queryset[index], validated_data) for index, validated_data in enumerate(validated_data_list) ] class CarModelSerializer(serializers.ModelSerializer): def validate(self, attrs): print(self.context) # 可以获得视图类在初始化序列化对象时传入的context # self.context.update({'a': 10}) # 序列化类内部更新context,传递给视图类 return attrs class Meta: # 配置自定义群增群改序列化类 list_serializer_class = BookListSerializer model = models.Car fields = ['name', 'is_delete', 'price', 'brand', 'brand_', 'updated_time', 'sponsors_'] extra_kwargs = { 'brand': { 'write_only': True, } # 'name':{ # 'required':False # }, # 'price': { # 'required': False # }, } class BrandModelSerializer(serializers.ModelSerializer): class Meta: model = models.Brand fields = ['name', 'is_delete', 'updated_time', 'car_list']
urls.py
from django.conf.urls import url from . import views from django.views.static import serve from d_car import settings urlpatterns = [ url(r'v1/car/$', views.CarAPIView.as_view()), url(r'v1/car/(?P<pk>\d+)/$', views.CarAPIView.as_view()), url(r'brand/$', views.BrandAPIView.as_view()), url(r'brand/(?P<pk>\d+)/$', views.BrandAPIView.as_view()), url(r'v2/car/$', views.CarV2APIView.as_view()), url(r'v2/car/(?P<pk>\d+)/$', views.CarV2APIView.as_view()), # url(r'v3/car/$', views.CarV3APIView.as_view()), # url(r'v3/car/(?P<pk>\d+)/$', views.CarV3APIView.as_view()), # 暴露文件夹 url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}), ]
视图家族
""" 视图基类:APIView、GenericAPIView 视图工具类:mixins包下的五个类(六个方法) 工具视图类:generics包下的所有GenericAPIView的子类 视图集:viewsets包下的类 """ """ GenericAPIView基类(基本不会单独使用,了解即可,但是是高级视图类的依赖基础) 1)GenericAPIView继承APIView,所有APIView子类写法在继承GenericAPIView时可以保持一致 2)GenericAPIView给我们提供了三个属性 queryset、serializer_class、lookup_field 3)GenericAPIView给我们提供了三个方法 get_queryset、get_serializer、get_obj """ """ mixins包存放了视图工具类(不能单独使用,必须配合GenericAPIView使用) CreateModelMixin:单增工具类 create方法 ListModelMixin:群查工具类 list方法 RetrieveModelMixin:单查工具类 retrieve方法 UpdateModelMixin:单整体局部改工具类 update方法 DestroyModelMixin:单删工具类 destory方法 """ """ generics包下的所有GenericAPIView的子类(就是继承GenericAPIView和不同mixins下的工具类的组合) 1)定义的视图类,继承generics包下已有的特点的GenericAPIView子类,可以在只初始化queryset和serializer_class两个类属性后,就获得特定的功能 2)定义的视图类,自己手动继承GenericAPIView基类,再任意组合mixins包下的一个或多个工具类,可以实现自定义的工具视图类,获得特定的功能或功能们 注: i)在这些模式下,不能实现单查群查共存(可以加逻辑区分,也可以用视图集知识) ii)DestroyModelMixin工具类提供的destory方法默认是从数据库中删除数据,所以一般删除数据的需求需要自定义逻辑 """
视图基类 APIView、GenericAPIView
视图基类:APIView、GenericAPIView
i)继承APIView的,所以拥有APIView的全部 ii)三个类属性:queryset、serializer_class、lookup_field iii)三个方法:get_queryset、get_serializer、get_object 过渡:单独继承GenericAPIView类的视图类,需要自己定义请求方法如get,还需要属性方法体完成请求
定义的视图类,自己手动继承GenericAPIView基类,再任意组合mixins包下的一个或多个工具类,可以实现自定义的工具视图类,获得特定的功能或功能们
# ----------------------------- 过渡写法:了解 ----------------------------- from rest_framework.generics import GenericAPIView class BookV1APIView(GenericAPIView): # 将数据和序列化提示为类属性,所有的请求方法都可以复用 queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer lookup_field = 'pk' # 可以省略,默认是pk,与url有名分组对应的 # 群查 def get(self, request, *args, **kwargs): # queryset = models.Book.objects.filter(is_delete=False).all() # => 方法+属性两行代码 queryset = self.get_queryset() # serializer = serializers.BookModelSerializer(instance=queryset, many=True) # => 方法+属性两行代码 serializer = self.get_serializer(instance=queryset, many=True) return APIResponse(results=serializer.data) # 单查 # def get(self, request, *args, **kwargs): # obj = self.get_object() # serializer = self.get_serializer(obj) # return APIResponse(results=serializer.data) # 单增 def post(self, request, *args, **kwargs): # serializer = serializers.BookModelSerializer(data=request.data) serializer = self.get_serializer(data=request.data) # 同样的步骤多了,好处就来了 serializer.is_valid(raise_exception=True) obj = serializer.save() return APIResponse(result=self.get_serializer(obj).data, http_status=201)
基于GenericAPIView的十大接口
views.py:
# 十大接口: # 1)单查、群查、单增、单整体改、单局部改都可以直接使用 # 2)单删不能直接使用,因为默认提供的功能是删除数据库数据,不是我们自定义is_delete字段值修改 # 3)除了群查以为的接口,都要自己来实现 # 注:给序列化类context赋值{'request': request},序列化类就可以自动补全后台图片链接
from rest_framework.generics import GenericAPIView from rest_framework import mixins from . import models, serializers from rest_framework.response import Response class BookV1APIView(GenericAPIView, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer def get(self, request, *args, **kwargs): if 'pk' in kwargs: return self.retrieve(request, *args, **kwargs) # 单查 # queryset = models.Book.objects.filter(is_delete=False).all() # 注:给序列化类context赋值{'request': request},序列化类就可以自动补全后台图片链接 # serializer = serializers.BookModelSerializer(queryset, many=True, context={'request': request}) # return Response(serializer.data) return self.list(request, *args, **kwargs) # 群查 def post(self, request, *args, **kwargs): if not isinstance(request.data, list): return self.create(request, *args, **kwargs) serializer = self.get_serializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=201, headers=headers) def delete(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: pks = [pk] else: pks = request.data try: rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True) except: return Response(status=400) if rows: return Response(status=204) return Response(status=400) def put(self, request, *args, **kwargs): if 'pk' in kwargs: return self.update(request, *args, **kwargs) pks = [] try: for dic in request.data: pks.append(dic.pop('pk')) objs = models.Book.objects.filter(is_delete=False, pk__in=pks) assert len(objs) == len(request.data) except: return Response(status=400) serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True) serializer.is_valid(raise_exception=True) objs = serializer.save() return Response(serializers.BookModelSerializer(objs, many=True).data) def patch(self, request, *args, **kwargs): if 'pk' in kwargs: return self.partial_update(request, *args, **kwargs) pks = [] try: for dic in request.data: pks.append(dic.pop('pk')) objs = models.Book.objects.filter(is_delete=False, pk__in=pks) assert len(objs) == len(request.data) except: return Response(status=400) serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True, partial=True) serializer.is_valid(raise_exception=True) objs = serializer.save() return Response(serializers.BookModelSerializer(objs, many=True).data)
视图工具类:mixins包
from rest_framework import mixins """ mixins包存放了视图工具类(不能单独使用,必须配合GenericAPIView使用) CreateModelMixin:单增工具类 create方法 ListModelMixin:群查工具类 list方法 RetrieveModelMixin:单查工具类 retrieve方法 UpdateModelMixin:单整体局部改工具类 update方法 DestroyModelMixin:单删工具类 destory方法 """
# ----------------------------- 过渡写法:了解 ----------------------------- from rest_framework.generics import GenericAPIView from rest_framework import mixins class BookV2APIView(GenericAPIView, mixins.RetrieveModelMixin, mixins.CreateModelMixin): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer # 单查 def get(self, request, *args, **kwargs): # obj = self.get_object() # serializer = self.get_serializer(obj) # return APIResponse(results=serializer.data) # return self.retrieve(request, *args, **kwargs) response = self.retrieve(request, *args, **kwargs) return APIResponse(result=response.data) # 单增 def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) # ----------------------------- 开发写法:常用 ----------------------------- from rest_framework.generics import RetrieveAPIView class BookV3APIView(RetrieveAPIView): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer # 单查 pass
工具视图类 generics工具包:继承指定类
generics包:工具视图类 i)系统完成的GenericAPIView与mixins包下工具类的不同组合 只需要配置三个类属性 ii)自己完成GenericAPIView与mixins包下工具类的不同组合 需要配置三个类属性,需要书写请求方法,如post,内部直接调用self.create方法 iii)自己继承一堆generics包下的工具视图,完成组合 只需要配置三个类属性,但是单查、群查不能共存
工具
继承指定的类,完成相应的功能
from rest_framework import generics 点进去看看又那些类 RetrieveAPIView : 单查 内部:get 方法写好了 ListAPIView :群查 内部:get 方法写好了 CreateAPIView :单增 内部:post 方法 DestroyAPIView : 单删 内部:delete 方法写好了 UpdateAPIView : 单整体改,单局部改 内部:put、patch 方法写好了 ListCreateAPIView : 群查,和单增 内部: get、post 方法写好了 ListCreateAPIView : 群增 内部:post方法 。。。
单查:
from rest_framework.generics import RetrieveAPIView class BookV3APIView(RetrieveAPIView): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer # 单查 RetrieveAPIView内部已经写好了get方法 pass
基于generics包下工具视图类的六大基础接口
六个必备:单查、群查、单增、单删、单整体改(了解),单局部该 四个额外接口:群增、群删、群整体改、群局部改 # 六大基础接口 # 1)直接继承generics包下的工具视图类,可以完成六大基础接口 # 2)单查群查不能共存,因为都是get方法 # 3)单删一般会重写
views.py:
from . import models, serializers from rest_framework.response import Response from rest_framework import generics class BookV2APIView(generics.ListAPIView, generics.RetrieveAPIView, generics.CreateAPIView, generics.UpdateAPIView, generics.DestroyAPIView): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer def get(self, request, *args, **kwargs): # 重写单查群查的get if 'pk' in kwargs: return self.retrieve(request, *args, **kwargs) return self.list(request, *args, **kwargs) def delete(self, request, *args, **kwargs): # 重写删除(不是真的删除数据,是修改字段) pk = kwargs.get('pk') models.Book.objects.filter(is_delete=False, pk=pk).update(is_delete=True) return Response(status=204)
视图集(开发常用,最高级)
路由组件(繁琐,可以自定义映射关系)
urls.py
url(r'^v3/books/$', views.BookV3APIView.as_view( {'get': 'list', 'post': 'create', 'delete': 'multiple_destroy'} )), url(r'^v3/books/(?P<pk>\d+)/$', views.BookV3APIView.as_view( {'get': 'my_list'} )),
views.py
from rest_framework.viewsets import ModelViewSet from rest_framework.response import Response class BookV3APIView(ModelViewSet): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer # 可以在urls.py中as_view({'get': 'my_list'})自定义请求映射 def my_list(self, request, *args, **kwargs): return Response('ok')
路由组件(简化)
urls.py
from django.conf.urls import url, include from . import views # 路由组件,必须配合视图集使用 from rest_framework.routers import SimpleRouter router = SimpleRouter() # 以后就写视图集的注册即可:BookV3APIView和BookV4APIView都是视图集 router.register('v3/books', views.BookV3APIView, 'book') router.register('v4/books', views.BookV4APIView, 'book') urlpatterns = [ url('', include(router.urls)) ]
视图组件 views.py
from rest_framework.viewsets import ReadOnlyModelViewSet class BookV4APIView(ReadOnlyModelViewSet): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer
重写删除方法:destroy
因为继承的删除方法:是真的删除了数据
我们修改的:修改is_delete字段
# 需要完成字段删除,不是重写delete方法,而是重写destroy方法 def destroy(self, request, *args, **kwargs): pk = kwargs.get('pk') models.Book.objects.filter(is_delete=False, pk=pk).update(is_delete=True) return Response(status=204)
群删接口
# 群删接口 def multiple_destroy(self, request, *args, **kwargs): try: models.Book.objects.filter(is_delete=False, pk__in=request.data).update(is_delete=True) except: return Response(status=400) return Response(status=204)
视图级使用总结
六个必备:单查、群查、单增、单删、单整体改(了解),单局部该 四个额外接口:群增、群删、群整体改、群局部改 # 注:给序列化类context赋值{'request': request},序列化类就可以自动补全后台图片链接 """ 视图集的使用总结 1)可以直接继承ModelViewSet,实现六大继承接口(是否重写destroy方法,或其他方法,根据需求决定) 2)可以直接继承ReadOnlyModelViewSet,实现只读需求(只有单查群查) 3)继承ViewSet类,与Model类关系不是很密切的接口:登录的post请求,是查询操作;短信验证码发生接口,借助第三方平台 4)继承GenericViewSet类,就代表要配合mixins包,自己完成任意组合 5)继承以上4个视图集任何一个,都可以与路由as_view({映射})配合,完成自定义请求响应方法 """
自定义路由组件(了解)
from rest_framework.routers import SimpleRouter as DrfSimpleRouter from rest_framework.routers import Route, DynamicRoute class SimpleRouter(DrfSimpleRouter): routes = [ # List route. Route( url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create', # 注:群增只能自己在视图类中重写create方法,完成区分 'delete': 'multiple_destroy', # 新增:群删 'put': 'multiple_update', # 新增:群整体改 'patch': 'multiple_partial_update' # 新增:群局部改 }, name='{basename}-list', detail=False, initkwargs={'suffix': 'List'} ), # Dynamically generated list routes. Generated using # @action(detail=False) decorator on methods of the viewset. DynamicRoute( url=r'^{prefix}/{url_path}{trailing_slash}$', name='{basename}-{url_name}', detail=False, initkwargs={} ), # Detail route. Route( url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', detail=True, initkwargs={'suffix': 'Instance'} ), # Dynamically generated detail routes. Generated using # @action(detail=True) decorator on methods of the viewset. DynamicRoute( url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', name='{basename}-{url_name}', detail=True, initkwargs={} ), ]
上传文件接口
urls.py
from django.conf.urls import url, include from . import views # 路由组件,必须配合视图集使用 from rest_framework.routers import SimpleRouter router = SimpleRouter() # /books/image/(pk) 提交 form-data:用image携带图片 router.register('books/image', views.BookUpdateImageAPIView, 'book') urlpatterns = [ url('', include(router.urls)) ]
serializers.py
class BookUpdateImageModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ['image']
views.py
# 上次文件 - 修改头像 - 修改海报 from rest_framework.viewsets import GenericViewSet from rest_framework import mixins class BookUpdateImageAPIView(GenericViewSet, mixins.UpdateModelMixin): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookUpdateImageModelSerializer
图片自动补全后台图片链接
queryset = models.Book.objects.filter(is_delete=False).all() # 注:给序列化类context赋值{'request': request},序列化类就可以自动补全后台图片链接 serializer = serializers.BookModelSerializer(queryset, many=True, context={'request': request}) return Response(serializer.data)
来源:https://www.cnblogs.com/guyouyin123/p/12355507.html