如何防止同一电影重复添加至Django Watchlist
解决Django观影清单重复添加问题
问题根源
原代码的add_watchlist视图存在两个核心问题:
- 检查逻辑错误:
Watchlist.objects.all()获取的是所有用户的观影记录,且直接用movie not in watchlist判断无效(watchlist是Watchlist对象集合,不是Movie对象) - 数据库层面无约束:即使视图逻辑修复,也可能因并发等情况出现重复数据
解决方案
1. 给Watchlist模型添加联合唯一约束
修改Watchlist模型,确保同一用户同一电影只能存在一条记录,从数据库层面杜绝重复:
from django.db import models from django.contrib.auth.models import User from Movies.models import Movie class Watchlist(models.Model): user=models.ForeignKey(User,on_delete=models.CASCADE) movie=models.ForeignKey(Movie,on_delete=models.CASCADE) quantity=models.IntegerField(default=1) date=models.DateField(auto_now_add=True) # 添加联合唯一约束(Django ≥2.2推荐写法) class Meta: constraints = [ models.UniqueConstraint(fields=['user', 'movie'], name='unique_user_movie_watchlist') ] # 兼容Django<2.2版本可替换为: # unique_together = ('user', 'movie') def __str__(self): return self.movie.name
2. 修复add_watchlist视图逻辑
修改视图中的检查逻辑,仅查询当前用户的观影记录,同时处理可能的重复添加场景:
from django.shortcuts import render,redirect from Movies.models import Movie from Watchlist.models import Watchlist from django.contrib import messages from django.db import IntegrityError def add_watchlist(request,p): user=request.user movie=Movie.objects.get(id=p) try: # 尝试创建记录,若已存在会触发IntegrityError异常 Watchlist.objects.create(user=user, movie=movie) messages.success(request, f"{movie.name} 已添加至观影清单") except IntegrityError: # 捕获重复添加异常,提示用户 messages.info(request, f"{movie.name} 已在你的观影清单中") finally: return redirect('Watchlist:view_watchlist')
3. 可选优化:提前检查避免异常
如果不想依赖异常捕获,也可以先查询当前用户是否已添加该电影:
def add_watchlist(request,p): user=request.user movie=Movie.objects.get(id=p) # 仅查询当前用户的观影记录,判断是否已存在 if not Watchlist.objects.filter(user=user, movie=movie).exists(): Watchlist.objects.create(user=user, movie=movie) messages.success(request, f"{movie.name} 已添加至观影清单") else: messages.info(request, f"{movie.name} 已在你的观影清单中") return redirect('Watchlist:view_watchlist')
补充说明
- 添加
messages提示可以让用户明确知晓操作结果,提升交互体验 - 模型层的唯一约束是最后一道防线,确保数据一致性,即便视图逻辑出现疏漏也不会产生重复数据
- 原视图中
watchlist=Watchlist.objects.all()的逻辑完全错误,既未过滤当前用户,也无法直接通过movie in watchlist判断(需对比每个Watchlist对象的movie字段)
内容的提问来源于stack exchange,提问作者Miguel O'Hara
相关产品推荐
相关产品推荐

