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

如何在Django中基于外键限制ModelChoiceField查询集?

解决方案:限制ModelChoiceField仅显示当前用户的Project

要实现仅让当前登录用户选择自己创建的Project,核心是把当前用户传递到表单中,再通过用户过滤Project的查询集。以下是具体修改步骤:

1. 修改RiddleForm,支持接收用户参数

更新forms.py中的RiddleForm,让它在初始化时接收当前用户,并用该用户过滤可选的Project:

from django import forms
from .models import Project, Riddle

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ['title', 'max_players', 'has_actor', 'scenario']

class RiddleForm(forms.ModelForm):
    # 初始查询集设为空,后续再根据用户赋值
    project = forms.ModelChoiceField(queryset=Project.objects.none(),
                                      empty_label=None,
                                      widget=forms.Select(attrs={'class': 'form-control'}),
                                      label='Project')

    class Meta:
        model = Riddle
        fields = ['project','description']

    # 新增user参数,用于过滤查询集
    def __init__(self, user=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if user:
            # 只显示当前用户创建的Project
            self.fields['project'].queryset = Project.objects.filter(user=user)
        self.fields['project'].label_from_instance = lambda obj: obj.title

2. 在视图中传递当前用户给表单

需要修改两个视图,在实例化RiddleForm时传入当前登录用户:

修改RiddleAddView

class RiddleAddView(CreateView):
    model = Riddle
    form_class = RiddleForm
    template_name = 'rooms/riddle_form.html'

    # 重写方法,将当前用户传递给表单
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

    # 简化form_valid逻辑:ModelChoiceField已返回正确的Project实例,无需重复查询
    def form_valid(self, form):
        return super().form_valid(form)

    def get_success_url(self):
       return reverse_lazy('rooms:project_detail', kwargs={'username': self.object.project.user.username, 'pk': self.object.project.id})

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 实例化表单时传入当前用户
        context['riddle_form'] = RiddleForm(user=self.request.user)
        return context

修改ProjectUpdateView

class ProjectUpdateView(UpdateView):
    model = Project
    form_class = ProjectForm
    template_name = 'rooms/project_form.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 传入当前用户到表单
        context['riddle_form'] = RiddleForm(user=self.request.user)
        return context

关键说明

你之前尝试filter()方法未成功,核心原因是表单无法直接获取当前请求的用户对象,必须通过视图将request.user传递给表单,才能在表单内部完成正确的查询集过滤。

内容的提问来源于stack exchange,提问作者Ilias Kaleridis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:02:53