如何在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
相关产品推荐
相关产品推荐

