You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:10:14