Django.DRF:ORM,Serializer,Filters,ModelViewSet,transaction

ORM  ,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法

Django修改表数据的两种方法:

# 第一种 <class 'django.db.models.query.QuerySet'>

info = User.objects.filter(id=request.user_id)
info.update(account=account)



# 第二种 <class 'user.models.User'>

info2 = User.objects.filter(id=request.user_id).first()
info2.name = name
info2.save()

ORM 查询操作 

.get()        得到一条数据,不存在则报错

.filter()         过滤查询 得到一个列表,不存在为空列表

.first()         从列表中取出第一条数据,是一个对象,不是列表

.filter().exclude()        排除当前表中某条数据

示例:

other_settings = ExamSetting.objects.filter(plan=plan).exclude(id=instance.id)

class Category(models.Model):
    cate_name = models.CharField(max_length=50, verbose_name='类别名')



class Goods(models.Model):
    cate = models.ForeignKey(Category, related_name='goods', on_delete=models.CASCADE, verbose_name='用户')


 

两表联查:1. 通过主表id 查询对应的 子表的数据:(反向查询)
 

cat=Category.objects.get(id=cate_id)

                     ------ 获取主表id对应的对象



goods_data = cat.goods_set.all()

                     ------ 对象.模型类小写_set.all()

                     ------ 获取子表中关联主表的对象的所有数据


2. 模型类添加属性 related_name
 

cat=Category.objects.get(id=cate_id)

                   ------ 获取主表id对应的对象



goods_data = cat.goods.all()

                   ------ 对象.related绑定对象.all()

related_name用于反向查询 cat.goods.all()
不定义的话 就是cat.goods_set.all()

 3. cate对象    cate_id对象的id (正向查询)

goods_queryset = Goods.objects.filter(cate_id=cate_id)

                  ----- 子表模型类.objects.filter(外键_id=主表的id)

查询ManyToManyField 多对多

class StudentGroup(models.Model):
    # 示例:TYPE
    TYPE = [
        ('news', '资讯'),
        ('notice', '公告')
    ]

    class Meta:
        db_table = 'group'

    category = models.CharField(max_length=10, choices=TYPE, verbose_name='类型')
    name = models.CharField(max_length=20, verbose_name='名称', unique=True, db_index=True)
    parent = models.ForeignKey(to='self', null=True, blank=True, on_delete=models.CASCADE, verbose_name='父级')
    students = models.ManyToManyField(to='Student', null=True, blank=True, verbose_name='学员')
    plans = models.ManyToManyField(to='Plan', null=True, blank=True, verbose_name='学习计划')
    note = models.CharField(max_length=120, null=True, blank=True, verbose_name='备注')
    link = models.CharField(max_length=10, null=True, blank=True, verbose_name='联系人')
    email = models.EmailField(max_length=100, null=True, blank=True, verbose_name='联系人邮箱')
    phone = models.CharField(max_length=20, null=True, blank=True, verbose_name='联系方式')
    create_user = models.ForeignKey(to='User', null=True, blank=True, related_name='user_create_uc_set',
                                    on_delete=models.PROTECT, verbose_name='创建人')
    write_user = models.ForeignKey(to='User', null=True, blank=True, related_name='user_write_uc_set',
                                   on_delete=models.PROTECT, verbose_name='修改人')

    def __str__(self) -> str:
        return self.name

获取学生群组中包含该学生的所有群组

student_groups = StudentGroup.objects.filter(students__id=student_id)
从上面的学生群组中获取关联的学习计划的 IDs

plan_ids = student_groups.values_list('plans', flat=True).distinct()
获取 Plan 对象

related_plans = Plan.objects.filter(id__in=plan_ids)
匹配查询符合对象id或对象列表的所有数据

planinfo_list = PlanInfo.objects.filter(plan_id__in=plan_ids)

planinfo_list = PlanInfo.objects.filter(plan__in=related_plans)

ORM语法补充

students = Student.objects.filter(pk__in=students_ids)

# pk 表中唯一标识,主键(Primary Key)的缩写

在PassagePlanInfo表中查询所有匹配学生id和匹配planinfos列表中对象的查询结果

在matching_records 查询结果中使用filter().exists()    结果返回为真,即return

planinfos=PlanInfo.objects.filter(plan=plan)
matching_records = PassagePlanInfo.objects.filter(
    student_id=student_id,
    plan_info__in=planinfos
)
if matching_records.filter(done=False).exists():
    return JsonResponse({'code': 400, 'msg': '有课程尚未学完,暂不能考试'})

检查是否存在DiplomaMyInfo关联记录


if DiplomaMyInfo.objects.filter(diploma=instance).exists():
   return Response({"detail": "不能删除,存在关联记录。"},status=status.HTTP_400_BAD_REQUEST)

modelviewset重新父类方法时调用父类方法

response = super().list(request, *args, **kwargs)

排除多对多关系中 active 字段为 True 的记录的

queryset = queryset.exclude(students__active=True)

排除当前表中 active 字段为 True 的记录的

queryset = self.filter_queryset(self.get_queryset()).filter(active=False)

any() 内置的 Python 函数,用于检查可迭代对象(如列表、元组、集合等)中是否至少有一个元素为 True 或等效于 True。如果至少有一个元素为真,则 any() 返回 True,否则返回 False。

lis = [None, None, 0]
flag = any(i for i in lis)

1.获取StudentGroup表中ManyToManyField字段的所有符合数据

2.获取相关所有计划, .values_list('')方法中可以回显id,或者用name 什么字段都行

student_groups = StudentGroup.objects.filter(students=student_id)

plan_ids = Plan.objects.filter(studentgroup__in=student_groups).values_list('id', flat=True)
 

Python方法补充

sum方法,满足条件,计数加1

sum(1 for item in subject_res if list(item.values())[0])

重组表字段信息 多条数据用for

class ContentApi(APIView):
    def get(self, request):
        new_info = []        
        content_info = Content.objects.all()    # 获取子表查询结果集
        for i in content_info:            # 循环出每条数据
            a = {            # 通过class对象调用字段的方法 重组一个新列表 
                'intro': i.intro,  # i是每一条数据的对象,i.intro就是对应这个对象的这条数据
                'cover': i.cover,
                'content_d': i.content_d,
                'head': i.article.head,            # (通过外键匹配添加主表字段)
                'qudao': i.article.qudao,            # article外键 qudao主表字段
                'pindao': i.article.pindao,
                'type': i.article.type,
                'key_word': i.article.key_word,
                'Issued_by': i.article.Issued_by,
                'time': i.article.time
            }
            new_info.append(a)        # 将每条数据匹配对应字段的数据 添加入空列表
        return Response({            
            'code': 200,
            'msg': '成功',
            'new_info': new_info
        })

一条数据重组:不需要添加列表,直接返回字典即可

class CouponInfo(APIView):
    # 修改时获取单条数据信息
    def get(self, request, id):
        try:
            cou = Coupon.objects.get(id=id)     # 1.从前端获取对象

            dic = {         # 2.重组订单 添加外键中其他表字段
                'id': cou.id,
                'name': cou.name,
                'brief': cou.brief,
                'coupon_type': cou.coupon_type.type_name,
                'sku_name': cou.good.name,
                'coupon_num': cou.coupon_num,
                'start_time': cou.start_time,
                'over_time': cou.over_time,
                'start_get_time': cou.start_get_time,
                'end_get_time': cou.end_get_time,
                'remark': cou.remark
            }

            return Response({'code': 200, 'msg': '获取优惠券信息成功', 'couponlist': dic})

        except:
            return Response({'code': 400, 'msg': '获取优惠券信息失败'})

serializers序列化

class StudentGroupSerializers(serializers.ModelSerializer):
    # 示例,  作用:添加本表中外键的名称 
    # student_name = serializers.CharField(source='student.username', read_only=True)
    
    # 示例,  作用:渲染出模型类 choices= 方法的枚举值
    # type = serializers.CharField(source='get_category_display', read_only=True)
    
    # 示例,  作用:序列化时不显示该字段
    # password = serializers.CharField(write_only=True)    

    # 示例,  作用:序列化时添加其他表中字段值
    # photo = serializers.SerializerMethodField()

    # 作用:添加多对多中的外键id和外键名称
    plans_id_name = serializers.SerializerMethodField()

    class Meta:
        model = models.StudentGroup
        # exclude = ['字段名']    不包括字段,exclude fields 看情况使用
        fields = "__all__"

    def get_plans_id_name(self, obj):    # obj为序列化器中当前对象
        plans_id_name_list = [[plan.id, plan.title] for plan in obj.plans.all()]
        return plans_id_name_list


    def get_photo(self, obj):
        # 检查是否存在关联的 MyInfo 实例
        my_info = MyInfo.objects.filter(student=obj).first()
        if my_info:
            return my_info.photo
        else:
            return None

filters过滤字段

class PassageFilter(filters.FilterSet):
    # 声明外键通过数字查询,好像不用声明,fields=__all__的时候就可以查
    category_id = filters.NumberFilter(field_name='category')

    # lookup_expr='icontains' 是用于执行不区分大小写的模糊查询(case-insensitive substring match)

    title = filters.CharFilter(field_name='title', lookup_expr='icontains')

    # 添加外键表中字段到过滤器中,可进行模糊查询
    plan_name = filters.CharFilter(field_name='plan__title', lookup_expr='icontains')
    myinfo_name = filters.CharFilter(field_name='myinfo__name', lookup_expr='icontains')

    # exact精确匹配,添加choices过滤
    topic_type = filters.ChoiceFilter(field_name='topic_type', lookup_expr='exact', choices=models.Topic.TYPE)


    class Meta:
        model = models.Passage
        fields = ('title', 'active', 'is_compute', 'subject')

ModelViewSet封装

from typing import Union

from rest_framework import status
from rest_framework.serializers import Serializer
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination


class BasePagination(PageNumberPagination):
    page_query_param = "page"
    page_size_query_param = 'page_size'  # 前端收到页面的关键字名称,默认是page
    max_page_size = 20  # 每页数据个数


class JsonModelViewSet(ModelViewSet):
    # 新增
    def create(self, request, *args, **kwargs):

        user = request.user
        request.data['create_user'] = user.id
        request.data['write_user'] = user.id

        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 JsonResponse(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    # 单查询
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return JsonResponse(serializer.data)

    # 修改
    def update(self, request, *args, **kwargs):

        user = request.user
        request.data['write_user'] = user.id

        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 JsonResponse(serializer.data)

    # 删除
    def destroy(self, request, *args, **kwargs):
        try:
            instance = self.get_object()
            instance.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        except ProtectedError as e:
            # 捕获 ProtectedError 异常
            # 返回适当的错误响应,例如 400 Bad Request
            return Response({'error': 'Related data exists. Cannot delete.'},
                            status=status.HTTP_400_BAD_REQUEST)
        except APIException as e:
            # 处理其他可能的异常
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # 查询
    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)
            response = self.get_paginated_response(serializer.data)
            return JsonResponse(response.data)

        serializer = self.get_serializer(queryset, many=True)
        return JsonResponse(serializer.data)


class JsonResponse(Response):
    def __init__(self, data=None, count=None, code=200, msg: Union[str, dict] = 'success',
                 status=None, template_name=None, headers=None,
                 exception=False, content_type=None, **kwargs):
        super().__init__(None, status=status)

        if isinstance(data, Serializer):
            msg = (
                'You passed a Serializer instance as data, but '
                'probably meant to pass serialized `.data` or '
                '`.error`. representation.'
            )
            raise AssertionError(msg)

        # 改变错误提示格式
        if isinstance(msg, dict):
            for k, v in msg.items():
                for i in v:
                    msg = "%s:%s" % (k, i)

        # 自定义返回格式
        self.data = {'code': code, 'msg': msg, 'data': data, 'count': count}
        self.data.update(kwargs)
        self.template_name = template_name
        self.exception = exception
        self.content_type = content_type

        if headers:
            for name, value in headers.items():
                self[name] = value

 

"""

ModelViewSet 默认方法

A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions.

"""

重写 create,update,get,list,方法

**kwargs >> 重组字典         .filter(**my_filter(request))     
 

  1. *args**kwargs 用于接受可变数量的参数。

    • *args 表示接受任意数量的位置参数(非关键字参数),它们会被收集成一个元组(tuple)。
    • **kwargs 表示接受任意数量的关键字参数,它们会被收集成一个字典(dictionary)。
  2. *** 也可以用于在函数调用时展开参数。

    • * 用于展开一个元组或列表,将其元素作为位置参数传递给函数。
    • ** 用于展开一个字典,将其键值对作为关键字参数传递给函数。

Django REST framework语法  

  1. 获取数据库对象(Get Object): 使用 self.get_object() 可以获取数据库中的特定对象,通常用于获取要操作的记录。

  2. 创建数据(Create Data): 使用 self.perform_create(serializer) 可以创建新的数据库记录,通常用于处理 POST 请求。

  3. 获取序列化器实例(Get Serializer Instance): 使用 self.get_serializer(instance) 可以获取一个序列化器的实例,通常用于读取对象数据并将其序列化为 JSON 格式。

    • serializer = self.get_serializer(instance)

      • 用于获取一个序列化器的实例,该实例用于将现有的数据库对象(通常是模型实例)序列化为数据,通常用于读取对象的数据。
    • serializer = self.get_serializer(data=request.data)

      • 用于获取一个序列化器的实例,该实例用于反序列化请求数据,通常在创建新对象时使用。data 参数包含请求中的数据,用于将其转换为对象。
    • serializer = self.get_serializer(instance, data=request.data)

      • 用于获取一个序列化器的实例,并将现有的数据库对象和请求数据传递给序列化器。通常在更新对象数据时使用,它会使用请求数据来更新对象字段。
    • serializer = self.get_serializer(instance, data=request.data, partial=True)

      • 类似于第三个语句,不同之处在于添加了 partial=True 参数。
      • 这意味着序列化器会执行部分更新,只更新请求中提供的字段,而不是全部字段。通常在处理部分更新(例如 PATCH 请求)时使用。
    • serializer = self.get_serializer(page, many=True)

      • 用于获取一个序列化器的实例,并传递一个包含多个对象的分页数据 page
      • 通常在处理分页数据时使用,例如获取一个包含多个对象的页面并将它们序列化为数据。
    • serializer = self.get_serializer(queryset, many=True)

      • 用于获取一个序列化器的实例,并传递一个查询集 queryset
      • 通常在处理查询集中的多个对象时使用,将这些对象序列化为数据。
  4. 验证序列化数据(Validate Serialized Data): 使用 serializer.is_valid(raise_exception=True) 来验证序列化后的数据是否有效。如果数据无效,将引发异常。

  5. 执行数据更新操作(Perform Data Update): 使用 self.perform_update(serializer) 来执行数据的更新操作,通常用于执行 PUT 或 PATCH 请求的操作。

  6. 删除数据库记录(Delete Database Record): 使用 instance.delete() 来删除数据库中的记录,通常用于处理 DELETE 请求。

  7. 获取适用于视图的查询集(Get Queryset for View): 使用 self.filter_queryset(self.get_queryset()) 来获取适用于当前视图的查询集。通常在视图类的 list 方法中使用。

  8. 分页(Pagination): 使用 self.paginate_queryset(queryset) 来进行分页。通常在视图类的 list 方法中使用。分页数据可用于构建响应。

  9. 构建响应(Build Response): 使用序列化器将数据序列化后,你可以使用 self.get_paginated_response(serializer.data) 构建响应,包括分页数据。这通常用于返回包含分页信息的 API 响应。

重写示例:

class StudentView(JsonModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializers

    filterset_class = StudentFilter
    pagination_class = BasePagination
    authentication_classes = [JWTAuthentication]

    def perform_create(self, serializer):
        return serializer.save()

    def perform_update(self, serializer):
        return serializer.save()

    # 注册用户
    def create(self, request, *args, **kwargs):
        password = request.data.get('password')
        hasher_password = make_password(password)
        request.data['password'] = hasher_password
        try:
            photo = request.data.pop('photo')
            name = request.data.pop('name')
            card = request.data.pop('card')
        except Exception as e:
            return JsonResponse(data={'code': 400, 'msg': '个人信息填写不完整'}, status=status.HTTP_400_BAD_REQUEST)
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        try:
            with transaction.atomic():
                student = self.perform_create(serializer)
                headers = self.get_success_headers(serializer.data)
                MyInfo.objects.create(
                    photo=photo, name=name, card=card, student=student
                )
                return JsonResponse(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
        except Exception as e:
            # raise exceptions.APIException(str(e))
            return JsonResponse(data={'code': 500, 'msg': str(e)}, status=status.HTTP_200_OK)

    # 修改
    def update(self, request, *args, **kwargs):
        user = request.user
        request.data['write_user'] = user.id
        password = request.data.get('password')
        if password:
            hasher_password = hashers.make_password(password)
            request.data['password'] = hasher_password
        try:
            photo = request.data.pop('photo')
            name = request.data.pop('name')
            card = request.data.pop('card')
            partial = kwargs.pop('partial', False)
        except Exception as e:
            return JsonResponse(data={'code': 400, 'msg': '个人信息填写不完整'}, status=status.HTTP_400_BAD_REQUEST)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        student = self.perform_update(serializer)
        myinfo = MyInfo.objects.filter(student=student)
        myinfo.update(
            photo=photo, name=name, card=card, student=student
        )
        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 JsonResponse(serializer.data)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)

        # 获取关联的 MyInfo 对象
        myinfo = MyInfo.objects.filter(student=instance).first()
        my_info_serializer = MyInfoSerializers(myinfo)
        my_dict = dict(serializer.data)
        my_dict['photo'] = my_info_serializer.data['photo']
        my_dict['name'] = my_info_serializer.data['name']
        my_dict['card'] = my_info_serializer.data['card']
        return JsonResponse(data=my_dict)

    def list(self, request, *args, **kwargs):
        # # 获取数据总量
        # count = self.queryset.count()
        # 获取过滤后的数量
        count_filtered = self.filter_queryset(self.get_queryset()).count()
        # 使用父类的 list 方法获取原始的 Response
        response = super().list(request, *args, **kwargs)
        # 在 Response 的 data 中添加 count 字段
        response.data['count'] = count_filtered
        return response

重写示例:

class StudentGroupView(JsonModelViewSet):
    queryset = StudentGroup.objects.all()
    serializer_class = StudentGroupSerializers
    filterset_class = StudentGroupFilter
    pagination_class = BasePagination
    authentication_classes = [JWTAuthentication]

    # 新建学员组并生成章节进度记录
    def create(self, request, *args, **kwargs):
        studentgroup_serializer = self.get_serializer(data=request.data)
        try:
            # 开启事务
            with transaction.atomic():
                if studentgroup_serializer.is_valid(raise_exception=True):
                    self.perform_create(studentgroup_serializer)
                    # 获取新建的对象
                    new_studentgroup = studentgroup_serializer.instance

                    headers = self.get_success_headers(studentgroup_serializer.data)
                    # 生成章节进度记录
                    students = new_studentgroup.students.all()
                    plans = new_studentgroup.plans.all()
                    for plan in plans:
                        planinfos = plan.planinfo_set.all()
                        for planinfo in planinfos:
                            passages = planinfo.subject.passage_set.all()
                            for passage in passages:
                                for student in students:
                                    passageplaninfo = PassagePlanInfo.objects.filter(
                                        passage=passage, plan_info=planinfo, student=student).first()
                                    if not passageplaninfo:
                                        PassagePlanInfo.objects.create(
                                            passage=passage, plan_info=planinfo, student=student
                                        )
                    return JsonResponse(studentgroup_serializer.data, status=status.HTTP_201_CREATED, headers=headers)
        # 捕获验证字段唯一性报错
        except ValidationError as e:
            error_data = {"code": 400, "msg": str(e), "data": None}
            return JsonResponse(data=error_data, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            raise exceptions.APIException(str(e))

    # 修改学员组并更新章节进度记录(修改时只新增学员和记录,不做删除学员和记录的操作)
    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        try:
            with transaction.atomic():
                # 获取传入的学员和学习计划的ID列表
                students_ids = request.data.get('students', [])
                plans_ids = request.data.get('plans', [])

                # 改变后的对象列表
                students = Student.objects.filter(pk__in=students_ids)
                plans = Plan.objects.filter(pk__in=plans_ids)

                # 当前对象列表
                current_students = instance.students.all()
                current_plans = instance.plans.all()

                # # 采用不删除,禁用学员的方法

                # students_deficiency = list(set(current_students) - set(students))
                # for student in students_deficiency:
                #     student.active = True
                #     student.save()

                # 将查询结果转为集合,可提高性能
                current_students_set = set(current_students)
                current_plans_set = set(current_plans)

                # 添加新学员和课程包
                students_list = []
                for student in students:
                    if student not in current_students_set:
                        students_list.append(student)
                        instance.students.add(student)
                for plan in plans:
                    if plan not in current_plans_set:
                        instance.plans.add(plan)
                instance.save()
                plans_list = instance.plans.all()
                # 新增学员生成章节进度记录
                for plan in plans_list:
                    planinfos = plan.planinfo_set.all()
                    for planinfo in planinfos:
                        passages = planinfo.subject.passage_set.all()
                        for passage in passages:
                            for student in students_list:
                                passageplaninfo = PassagePlanInfo.objects.filter(
                                    passage=passage, plan_info=planinfo, student=student).first()
                                if not passageplaninfo:
                                    PassagePlanInfo.objects.create(
                                        passage=passage, plan_info=planinfo, student=student
                                    )
                # 删除学员组中被删除学员的生成记录
                students_deficiency = list(set(current_students) - set(students))
                plans_deficiency = list(set(current_plans) - set(plans))
                student_group = StudentGroup.objects.get(pk=int(kwargs.get('pk')))

                for student in students_deficiency:
                    passageplaninfos = []
                    for plan in current_plans:
                        plan_infos = plan.planinfo_set.all()
                        for plan_info in plan_infos:
                            # 学生是否能删
                            passageplaninfo = PassagePlanInfo.objects.filter(student=student, plan_info=plan_info)
                            passageplaninfos.extend(passageplaninfo)
                    flag = any(p.have_play for p in passageplaninfos)
                    if not flag:
                        for i in passageplaninfos:
                            i.delete()
                        student_group.students.remove(student)
                # 课程包是否能删
                for plan in plans_deficiency:
                    ppinfo = []
                    plan_infos = plan.planinfo_set.all()
                    for planinfo in plan_infos:
                        ppinfo2 = PassagePlanInfo.objects.filter(plan_info=planinfo)
                        for i in ppinfo2:
                            ppinfo.append(i)
                    f = any(p.have_play for p in ppinfo)
                    if not f:
                        for i in ppinfo:
                            i.delete()
                        student_group.plans.remove(plan)
                studentgroup_serializer = self.get_serializer(instance, data=request.data, partial=True)
                if studentgroup_serializer.is_valid(raise_exception=True):
                    self.perform_update(studentgroup_serializer)
                return JsonResponse(studentgroup_serializer.data, status=status.HTTP_200_OK)
        except ValidationError as e:
            error_data = {"code": 400, "msg": str(e), "data": None}
            return JsonResponse(data=error_data, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            raise exceptions.APIException(str(e))

重写示例: 

class TopicView(JsonModelViewSet):
    queryset = Topic.objects.all()
    serializer_class = TopicSerializers
    filterset_class = TopicFilter
    pagination_class = BasePagination
    authentication_classes = [JWTAuthentication]
    TYPE_MAPPING = {
        '单选题': 'one',
        '多选题': 'many',
        '判断题': 'bool'
    }

    def create(self, request, *args, **kwargs):
        try:
            # 将传递的中文topic_type转换为英文标识
            topic_type_chinese = request.data.get('topic_type')
            topic_type_english = self.TYPE_MAPPING.get(topic_type_chinese)
            request.data['topic_type'] = topic_type_english
            # 进行你的数据库操作,例如创建Topic对象
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            self.perform_create(serializer)

        except Exception as e:
            if 'Duplicate entry' in str(e):
                # raise exceptions.APIException("重复条例!无法添加试题")
                return JsonResponse(data={'code': 400, 'msg': "重复条例!无法添加试题"}, status=status.HTTP_400_BAD_REQUEST)
            raise exceptions.APIException(str(e))
        # 返回正常的响应
        return JsonResponse(data={'code': 201, 'msg': '试题添加成功'}, status=status.HTTP_201_CREATED)

重写filters过滤器 

# 精确查询
def my_filter(request) -> dict:
    data_dict = {}
    for key, value in request.GET.items():
        data_dict[key] = value
    return data_dict



# 补充 >> 模糊查询:
# 获取查询参数

from django.db.models import Q

query_params = my_filter(request)

# 创建一个空的Q对象,用于构建查询
query = Q()

# 对每个查询参数进行模糊查询构建
for key, value in query_params.items():
   # 对于每个参数,使用icontains进行模糊匹配
   query |= Q(**{f'{key}__icontains': value})
queryset = self.get_queryset().filter(query)




示例:
class ExamTopicView(ModelViewSet):
    queryset = ExamTopic.objects.all()
    serializer_class = ExamTopicSerializers
    filterset_class = ExamTopicFilter
    pagination_class = BasePagination

    def list(self, request, *args, **kwargs):
        token = request.headers.get('Authorization')
        if not token:
            return JsonResponse({"code": 401, 'message': 'Authorization header not found'})
        student_id = tokenreq(token)
        if not student_id:
            return JsonResponse({'code': 401, 'message': 'token is error,Please login again'})

        queryset = self.get_queryset().filter(**my_filter(request))
        count = queryset.count()
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            response = self.get_paginated_response(serializer.data)
            return JsonResponse(response.data)

        serializer = self.get_serializer(queryset, many=True)
        print('serializer', type(serializer.data))
        return JsonResponse(data=serializer.data, count=count)

APIView 上传

class UploadView(APIView):
    def post(self, request):
        file = request.FILES.get('file')
        BASE_DIRS = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
        path_url = os.path.join(BASE_DIRS, 'static', 'file')
        if not os.path.exists(path_url):
            # 判断目录是否存在,若不存在则递归创建目录
            os.makedirs(path_url)

        file_name = file.name
        file_type = file_name.split('.')[-1]
        file_name2 = file_name[:file_name.rfind('.')]

        # 生成唯一的文件名
        unique_filename = datetime.now().strftime('%Y%m%d%H%M%S') + str(
            random.randint(100000, 999999)) + '_' + file_name
        file_path = os.path.join(path_url, unique_filename)
        with open(file_path, 'wb') as f:
            f.write(file.read())
        data = {'file_type': file_type, 'file_name': file_name2, 'file_path': file_path}
        return JsonResponse(data=data)

事务

# 测试接口
class TestApi(APIView):
    def post(self, request):
        data = request.data
        data['subject_id'] = data.pop('subject')
        try:
            with transaction.atomic():
                Topic.objects.create(**data)
                # Topic.objects.get(id=300)     # 被动触发异常 >>> 回滚
                # return Response(data={'msg': 'ok'}, status=200)
                # raise exceptions.APIException('手动抛异常 >>> 回滚')
                return JsonResponse(data={'code': 201, 'msg': '添加成功'}, status=status.HTTP_201_CREATED)
        except Exception as e:  # 只要代码通过try进来,transaction模块中全部回滚
            print(str(e))
            if 'matching query does not exist' in str(e):
                return Response(data={'error': str(e)}, status=400)     # 捕获特定异常
            # return Response(data={'error': str(e)}, status=402)
            raise exceptions.APIException(str(e))

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值