Django登录用户分类名称重复校验问题求助
解决登录用户分类名称唯一校验问题
核心问题拆解
- 当前表单校验逻辑查询所有用户的分类数据(
Category.objects.all()),导致跨用户的名称冲突校验 - 表单无法直接获取
request.user,需通过视图主动传递参数 - 分类保存时未关联当前登录用户,导致分类归属错误且后续校验逻辑失效
具体修正步骤
1. 改造CategoryForm,支持接收用户参数
在表单的构造方法中提取并保存用户信息,校验时仅查询当前用户的分类:
class CategoryForm(forms.ModelForm): add_category = forms.BooleanField(widget=forms.HiddenInput, initial=True) def __init__(self, *args, **kwargs): self.user = kwargs.pop('user', None) # 取出user参数并保存到实例 super().__init__(*args, **kwargs) class Meta: model = Category fields = ['name'] def clean_name(self): name = self.cleaned_data.get('name') if not name: raise forms.ValidationError('This field cannot be left blank') # 仅查询当前用户的分类数据 queryset = Category.objects.filter(user=self.user) # 编辑场景下排除当前分类实例,避免自身名称校验冲突 if self.instance.pk: queryset = queryset.exclude(pk=self.instance.pk) if queryset.filter(name=name).exists(): raise forms.ValidationError(f'There is a category with the name {name}') return name
2. 修正首页视图,传递用户并关联分类归属
实例化表单时传入request.user,保存分类时绑定当前用户:
@login_required def index(request): categories = Category.objects.filter(user=request.user) items = Item.objects.all() add_item = ItemForm() # 初始化表单时传入当前用户 add_category = CategoryForm(user=request.user) query = None if request.method == 'POST': if 'add_item' in request.POST: add_item = ItemForm(request.POST) if add_item.is_valid(): form = add_item.save(commit=False) form.category = get_object_or_404( Category, name=request.POST.get('category'), user=request.user) add_item.save() return redirect('home') else: # 提交表单时同样传入当前用户 add_category = CategoryForm(request.POST, user=request.user) if add_category.is_valid(): category_form = add_category.save(commit=False) category_form.user = request.user # 绑定当前登录用户 category_form.save() messages.success(request, f'{category_form.name} has been added') return redirect('home')
3. 修正分类编辑视图,传递用户并限制编辑权限
仅允许用户编辑自己的分类,同时传递用户参数到表单:
@login_required def category_edit(request, pk): # 只查询当前用户的分类,防止越权编辑 category = get_object_or_404(Category, id=pk, user=request.user) if request.method == 'POST': form = CategoryForm(request.POST, instance=category, user=request.user) if form.is_valid(): form.save() messages.info(request, f'{category.name} has been updated!') return redirect('home') else: form = CategoryForm(instance=category, user=request.user) context = { 'form': form, } return render(request, 'category_edit.html', context)
4. 数据库层面添加唯一约束(可选但推荐)
在模型中添加联合唯一约束,从底层保证同一用户下分类名称不重复:
class Category(models.Model): user = models.ForeignKey(User, default=1, on_delete=models.CASCADE, related_name='category', null=True) name = models.CharField(max_length=100, null=False, blank=False) slug = models.SlugField(max_length=100) created_on = models.DateTimeField(auto_now_add=True) timestamp = models.DateTimeField(auto_now=True) class Meta: ordering = ['-timestamp'] verbose_name = 'category' verbose_name_plural = 'categories' # 同一用户下分类名称唯一 unique_together = ('user', 'name') def __str__(self): return self.name def get_absolute_url(self): return reverse('category_detail', kwargs={'slug': self.slug})
内容的提问来源于stack exchange,提问作者EddieStn
相关产品推荐
相关产品推荐

