如何在Django ModelSelect2Widget中自定义过滤queryset
实现方案
完全可以在ModelSelect2Widget中实现自定义queryset过滤,根据你的使用场景,选以下任意一种方式即可:
方式1:在自定义Widget内全局配置过滤规则
如果所有使用UsersWidget的场景都需要过滤出允许接收私信的用户,直接重写Widget的get_queryset方法即可:
class UsersWidget(s2forms.ModelSelect2Widget): search_fields = [ "name__icontains", "email__icontains", ] def get_queryset(self): # 仅返回开启了私信权限的用户 return super().get_queryset().filter(allow_direct_messages=True)
这个配置是全局生效的,所有引用该Widget的表单都会自动应用这个过滤逻辑,包括Select2的异步搜索接口返回的结果也会走这个过滤,不会出现搜索出无权限用户的问题。
方式2:在表单内单独配置当前场景的过滤规则
如果你需要在不同表单里给同一个UsersWidget配置不同的过滤规则,不需要改Widget本身,直接在表单初始化时给对应字段指定queryset即可:
class DirectMessageCreateForm(forms.ModelForm): class Meta: model = DirectMessage fields = ("author", "recipient", "content") labels = { "author": "", } widgets = { "recipient": UsersWidget, "content": forms.Textarea(attrs={ 'class': 'block p-3 w-full text-md bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500' ' focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 ' 'dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500', 'placeholder': "Type your message here..." }), "author": forms.TextInput, } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 仅在当前私信表单中过滤允许收私信的用户 self.fields['recipient'].queryset = User.objects.filter(allow_direct_messages=True)
扩展:更复杂的过滤逻辑
如果需要加额外规则,比如不允许用户给自己发私信,可以在Widget的get_queryset方法里通过self.request获取当前登录用户,追加过滤条件:
def get_queryset(self): qs = super().get_queryset().filter(allow_direct_messages=True) # 排除当前登录用户 if self.request.user.is_authenticated: qs = qs.exclude(pk=self.request.user.pk) return qs
注意:正常按照标准流程集成django-select2的前提下,Widget实例会自动注入request属性,不需要额外传参。
内容的提问来源于stack exchange,提问作者Bohdan Sizomin
相关产品推荐
相关产品推荐

