如何用Django View Set实现课程收藏的重复添加校验?
解决课程收藏重复添加的问题
一、修正模型(添加唯一性约束)
你的MyCoursesList模型缺少用户与课程的唯一性校验,导致同一用户可以重复收藏同一课程。需要添加约束确保组合唯一:
class MyCoursesList(models.Model): user = models.ForeignKey('accounts.User', on_delete=models.CASCADE, blank=True) courses = models.ForeignKey(Courses, on_delete=models.CASCADE, blank=True, related_name='my_courses') added_date = models.DateTimeField(auto_now_add=True) teacher = models.ForeignKey(Teacher, on_delete=models.DO_NOTHING, default=1) class Meta: # 强制同一用户不能重复收藏同一课程 unique_together = ('user', 'courses') # Django 2.2+ 推荐用以下写法替代unique_together # unique_constraints = [ # models.UniqueConstraint(fields=['user', 'courses'], name='unique_user_course') # ]
二、重构视图逻辑
原视图用ModelViewSet会附带很多不必要的接口(比如列表、更新),且错误地在get_queryset中处理创建逻辑。我们改用ViewSet重写create方法,实现校验与收藏逻辑:
from rest_framework import viewsets, status from rest_framework.response import Response from django.shortcuts import get_object_or_404 from .models import MyCoursesList, Courses from .serializers import MyCoursesListSerializer class AddtoMyCoursesView(viewsets.ViewSet): serializer_class = MyCoursesListSerializer def create(self, request): # 获取当前登录用户(需确保接口已做登录校验) current_user = request.user course_id = request.data.get('pk') # 参数校验:课程ID不能为空 if not course_id: return Response({'error': '课程ID不能为空'}, status=status.HTTP_400_BAD_REQUEST) # 校验课程是否存在 course = get_object_or_404(Courses, id=course_id) # 检查当前用户是否已收藏该课程 if MyCoursesList.objects.filter(user=current_user, courses=course).exists(): return Response({'message': '您已收藏过该课程'}, status=status.HTTP_400_BAD_REQUEST) # 未收藏则创建收藏记录 serializer = self.serializer_class(data={ 'courses': course.id, # 若课程关联了教师,自动从课程中获取教师ID,替代默认值1 'teacher': course.teacher.id if hasattr(course, 'teacher') else 1 }) if serializer.is_valid(): # 自动传入当前用户,无需前端传参 serializer.save(user=current_user) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
三、序列化器优化(可选)
如果希望用户字段无需前端传入,可在序列化器中设置为只读:
from rest_framework import serializers from .models import MyCoursesList class MyCoursesListSerializer(serializers.ModelSerializer): class Meta: model = MyCoursesList fields = ['id', 'user', 'courses', 'added_date', 'teacher'] # 设置user为只读,由视图自动传入 read_only_fields = ['user']
原代码问题说明
ModelViewSet不适合单一的收藏创建场景,会生成多余接口;get_queryset方法被错误用于处理创建逻辑,该方法的作用是返回视图操作的查询集,而非处理请求;exists()返回布尔值,无法解包为两个变量,且未关联当前用户,导致校验逻辑错误;- 缺少用户与课程的唯一性约束,即使视图校验通过,数据库层面仍可能出现重复数据。
内容的提问来源于stack exchange,提问作者Ashti Nematian
相关产品推荐
相关产品推荐

