drf表操作

Posted tangceng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了drf表操作相关的知识,希望对你有一定的参考价值。

drf表操作

一、面向对象二次封装Response

? 为方便多次调用Response方法,可将Response进行二次封装

? response.py:

from rest_framework.response import Response


class APIResponse(Response):
    # 格式化data
    def __init__(self, status=0, msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs):
        data = {  # json的response基础有数据状态码和数据状态信息
            'status': status,
            'msg': msg
        }
        if results is not None:  # 后台有数据,响应数据
            data['results'] = results
        data.update(**kwargs)  # 后台的一切自定义响应数据直接放到响应数据data中
        super().__init__(data=data, status=http_status, headers=headers, exception=exception)

? views.py:

class BookAPIView(APIview):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            book_obj = models.Book.bojects.filter(pk=pk).first()
            if not boot_obj:
                # 以下内容被封装
                # return Response({
                #     'status': 1,
                #     'msg': 'pk error'
                # }, status=400)
                return APIResponse(1, 'pk error', http_static=400)
            book_data = serializers.BookModelSerializer(book_obj).data
                        # return Response({
            #     'status': 0,
            #     'msg': 'ok',
            #     'results': car_data
            # })
            return APIResponse(results=book_data)

二、模型基表

? Model类的内部配置Meta类要设置abstract=True,这样的Model类就是用来作为基表。

? models.py:

class BookModel(models.Model):
    is_delete = models.BooleanField(default=False)
    create_time = models.DateField(auto_now_add=Ture)
    
    class Meta:
        # 基表必须设置abstract,基表就是给普通Model类继承使用的,设置了abstract就不会完成数据库迁移完成建表
        abstract = Ture

三、多表ORM关联操作

3.1 表断关联

? 1、表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)

? 2、断关联后不会影响数据库查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)

? 3、断关联一定要通过逻辑保证表之间数据的安全

? 4、断关联

? 5、级联关系:

? 作者没了,详情也没:on_delete=models.CASCADE

? 出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING

? 部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL

? 部门没了,员工进入默认部门(默认值):default=0, on_delete=models.SET_DEFAULT

? models.py:

class Book(BaseModel):
    name = models.CharField(max_length=16)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
    # 多对多外键实际在关系表中,ORM默认关系表中两个外键都是级联
    # ManyToManyField字段不提供设置on_delete,如果想设置关系表级联,只能手动定义关系表
    author = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
    
    # 自定义连表深度,不需要反序列化,因为自定义插拔属性不参与反序列化
    @property
    def publish_name(self):
        return self.publish.name
    
    @property
    def author_list(self):
        temp_author_list = []
        for author in self.authors.all():
            temp_author_list.append({
                'name': author.name,
                'sex': author.get_sex_display(),
                'mobile': author.detail.mobile
            })
        return temp_author_list
    
class Publish(baseModel):
    name = models.CharField(max_length=16)
    sex = models.IntegerField(choices=[(0,'男'),(1,'女')], default=0)
    
class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11)
    # 有作者可以没有详情,删除作者,详情一定会被级联删除
    # 外键字段为正向查询字段,related_name是反向查询字段
    autor = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)

3.2 ORM外键设计

? 1、一对多:外键放在多的一方

? 2、多对多:外键放在常用的一方

? 3、一对一:外键放在不常用的一方

? 4、外键字段为正向查询字段,related_name是反向查询字段

四、连表序列化

? serializers.py:

class BookListSerializer(serializers.ListSerializer):
    # 1、create方法父级ListSerializer已经提供了
    # 2、父级ListSerializer没有通过update方法的实现体,需要重写
    def update(self, instance, validated_data):
        return [
            self.child.update(instance[i],attrs) for i,attrs in enumerate(validated_data)
        ]
    
class BookModelSerializer(serializers.ListSerializer)
    # 通过BookModelSerializer.Meta.list_serializer_class来访问绑定的ListSerializer
    class Meta:
        list_serializer_class = BookListSerializer
        model = moldes.Book
        # 序列化反序列化整合
        fields = ('name', 'price', 'publish_name', 'author_list', 'publish', 'authors')
        extra_kwargs = {
            'publish': {
                'wite_only': Ture
            },
            'authors': {
                'wite_only': Ture
            }
        }
        
class PublishModelSerializer(serializers.ModelSerializer):
    # 子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False;不唯一:many=True
    # 注:只能参与序列化,且反序列化不能写(反序列化外键字段会抛异常)
    books = BookModelSerializer(many=True)
    class Meta:
        model = models.Publish
        field = ('name', 'address', 'books')

五、单查群查序列化

? views.py:

class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
            if not book_obj:
                return APIResponse(1, 'pk error', http_status=400)
            book_data = serializers.BookModelSerializer(book_obj).data
            return APIResponse(results=book_data)
        book_query = models.Book.objects.filter(is_delete=False).all()
        return APIResponse(0, 'ok', data=serializers.BookModelSerializer(book_query, many=True).data)

六、单删群删接口

def delete(self, request, *args, **kwargs):
    pk = kwargs.get('pk')
    if pk:
        pks = [pk]
    else:
        pks = request.data.get('pks')
    if not pks:
        return APIResponse(1, 'delete error', http_status=400)
    rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=Ture)
    if rows:
        return APIResponse(0,'delete ok')
    return APIResponse(1, 'delete failed')

七、单增群增接口

def post(self, request, *args, **kwargs):
    request_data = request.data
    # 单增
    if isinstance(request_data, dict)
        book_ser = serializers.BookModelSerializer(data=request_data)
        if book_ser.is_valid():
            book_obj = book_ser.save()
            return APIResponse(results=serializers.BookModelsSerializer(book_obj).data)
        return APIResponse(1, msg=book_ser.errors)
    elif isinstance(request_data, list)and len(request_data) != 0: #群增 
        book_ser = serializers.BookModelSerializer(data=request_data, many=Ture)
        book_ser.is_valid(raise_exception=True)
        book_obj_list = book_ser.save()
        return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
        else:
            return APIResponse(1, 'data error', http_status=400)

八、单整体改、群整体改

def put(self, request, *args, **kwargs):
    pk = kwargs.get('pk')
    request_data = request.data
    if pk:  # 单改
        try:
            book_obj = models.Book.objects.get(pk=pk)
        except:
            return APIResponse(1, 'pk error')
        # 修改和新增,都需要通过数据,数据依旧给data,修改与新增不同点,instance要被赋值为被修改对象
            book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
            return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
    else:  # 群改
        if not isintance(request_data, list) or len(request_data) == 0:
            return APIResponse(1, 'data error', http_status=400)
        
        obj_list = []
        data_list = []
        for dic in request_data:
            try:
                pk = dic.pop('pk')
                try:
                    obj = models.Book.objects.get(pk=pk, is_delete=False)
                    obj_list.append(obj)
                    data_list.append(dic)
                except:
                    pass
            except:
                return APIResponse(1, 'data error', http_status=400)

        book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True)
        book_ser.is_valid(raise_exception=True)
        book_obj_list = book_ser.save()
        return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)

九、单局部与群局部修改

def patch(self, request, *args, **kwargs):
    pk = kwargs.get('pk')
    request_data = request.data
    if pk:
        try:
            book_obj = models.Book.objects.get(pk=pk)
        except:
            return APIResponse(1, 'pk error')
        book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=Ture)
        book_ser.is_valid(raise_exception=Ture)
        book_obj = book_ser.save()
        return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
    
    else: # 群增
        if not isinstance(request_data, list) or len(request_data) == 0:
            return APIResponse(1, 'data error', http_status=400)
        # 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作
        obj_list = []
        data_list = []
        for dic in request_data:
            # request_data可能是list,单内部不一定是dict
            try:
                pk = dic.pop('pk')
                try:
                    obj = models.Book.objects.get(pk=pk, is_delete=False)
                    obj_list.append(obj)
                    data_list.append(dic)
                except:
                    pass
            except:
                return APIResponse(1, 'data error', http_status=400)

        book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True, partial=True)
        book_ser.is_valid(raise_exception=True)
        book_obj_list = book_ser.save()
        return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)

以上是关于drf表操作的主要内容,如果未能解决你的问题,请参考以下文章

drf多表操作

drf多表断表操作

DRF4级联与外键字段

drf 权限校验设置与源码分析

drf中的序列化家族

DRF十大请求