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))
*args
和**kwargs
用于接受可变数量的参数。
-
*args
表示接受任意数量的位置参数(非关键字参数),它们会被收集成一个元组(tuple)。 -
**kwargs
表示接受任意数量的关键字参数,它们会被收集成一个字典(dictionary)。
*
和**
也可以用于在函数调用时展开参数。
-
*
用于展开一个元组或列表,将其元素作为位置参数传递给函数。 -
**
用于展开一个字典,将其键值对作为关键字参数传递给函数。
Django REST framework语法
- 获取数据库对象(Get Object): 使用
self.get_object()
可以获取数据库中的特定对象,通常用于获取要操作的记录。 - 创建数据(Create Data): 使用
self.perform_create(serializer)
可以创建新的数据库记录,通常用于处理 POST 请求。 - 获取序列化器实例(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
。 - 通常在处理查询集中的多个对象时使用,将这些对象序列化为数据。
- 验证序列化数据(Validate Serialized Data): 使用
serializer.is_valid(raise_exception=True)
来验证序列化后的数据是否有效。如果数据无效,将引发异常。 - 执行数据更新操作(Perform Data Update): 使用
self.perform_update(serializer)
来执行数据的更新操作,通常用于执行 PUT 或 PATCH 请求的操作。 - 删除数据库记录(Delete Database Record): 使用
instance.delete()
来删除数据库中的记录,通常用于处理 DELETE 请求。 - 获取适用于视图的查询集(Get Queryset for View): 使用
self.filter_queryset(self.get_queryset())
来获取适用于当前视图的查询集。通常在视图类的list
方法中使用。 - 分页(Pagination): 使用
self.paginate_queryset(queryset)
来进行分页。通常在视图类的list
方法中使用。分页数据可用于构建响应。 - 构建响应(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))