使用包含 RadioSelect 小部件的 ModelChoiceField 在 ModelForm 的查询集中获取 request.user

Posted

技术标签:

【中文标题】使用包含 RadioSelect 小部件的 ModelChoiceField 在 ModelForm 的查询集中获取 request.user【英文标题】:Get request.user in queryset in a ModelForm with a ModelChoiceField that contains a RadioSelect widget 【发布时间】:2015-10-09 15:55:06 【问题描述】:

关于将request.user 传递给ModelForm 中的queryset,我想向社区提出以下问题。我的ModelForm 是:

class goForm(ModelForm): 
    user_choice = goModelChoiceField(
            widget=forms.Radioselect,
            queryset=Document.objects.all().filter(who_upload=request.user),
            empty_label=None,
            to_field_name='docfile',
            label = 'Please select'
            )            
    class Meta:
        model = go
        fields = ['user_choice']

class goModelChoiceField(forms.ModelChoiceField):
        def label_from_instance(self, obj):
            return  "'%s' uploaded on %s" % (obj.file_name, 
                obj.when_upload.date()) 

我找到的所有答案都是指将request.user 传递给__init__ 或使用过滤后的选择填充视图中的goForm。但是,在我的情况下似乎没有任何效果,因为我已经对表单进行了子类化以返回特定的字符串,而且我正在使用 RadioSelect 小部件特别需要 queryset 作为参数(我对此不是 100% 确定)。那么如何在user_choice 中传递request.user 呢?

【问题讨论】:

__init__ 中执行此操作是完全正确的解决方案,您拥有自定义类这一事实无关紧要。请展示您尝试过的内容以及遇到的错误。 请检查您的代码的缩进。将 goModelChoiceField 放在 ModelForm 中可能是个坏主意(它会使代码混乱并阻止您在其他类中重用它)。在goModelChoiceField 中定义user_choice 肯定是错误的。 @Alasdair :是的,我意识到,我将user_choice 移到goModelChoiceForm 之外和Meta 类中。奇怪的是它是如何以两种方式工作的。谢谢。 user_choice 字段也不应该在 Meta 类中定义。 不,如果它在 Meta 中,它根本不起作用:Django 不希望在那里定义字段。你应该将 goModelChoiceField 变成一个独立的类;嵌套类在 Python 中没有任何好处。这些事情都不会影响你如何通过request.user,这仍然需要在__init__中完成。 【参考方案1】:

model choice field docs 展示了如何在__init__ 方法中设置查询集。

class goForm(ModelForm): 
    user_choice = goModelChoiceField(
        widget=forms.RadioSelect,
        queryset=None,
        empty_label=None,
        to_field_name='docfile',
        label = 'Please select'
        )            

    def __init__(self, user, *args, **kwargs):
        super(goForm, self).__init__(*args, **kwargs)
        self.fields['user_choice'].queryset = Document.objects.all().filter(who_upload=user)

    class Meta:
        model = go
        fields = ['user_choice']

请注意,__init__ 方法现在将用户作为参数,因此请记住在视图中实例化表单的任何位置传递它。例如:

form = goForm(user=request.user, data=request.POST)

【讨论】:

很高兴它对你有用。最后一点建议 - 我建议将模型重命名为 Go,将表单重命名为 GoForm 等。Django 模型通常大写,小写形式用于单个实例,例如 go = Go.objects.get(id=10) 非常感谢Alasdair。如果我可以问另一个问题。您的解决方案虽然在有 GET 时似乎渲染得很好,但是当有 POST 时,当参数序列是您在解决方案中给出的序列时,它要么给出non-keyword arg after keyword arg(即:(user=request.user,data =request.POST)` 并通过交换订单给出__init__() got multiple values for keyword argument 'user'。我怀疑我应该保留第一个订单,但我怎样才能避免这个错误?再次感谢Alasdair 看来上面的解决方案不是改变__init__的签名而是用user = kwargs.pop('user', None)得到user(参考this),这就是为什么我编辑了你的答案。 您可以通过在 __init__ 签名中包含用户或从 kwargs 中弹出它来使代码正常工作。如果您将所有参数都作为关键字参数提供,您不应该在我的代码中获得 non-keyword arg after keyword arg

以上是关于使用包含 RadioSelect 小部件的 ModelChoiceField 在 ModelForm 的查询集中获取 request.user的主要内容,如果未能解决你的问题,请参考以下文章

如何将 CSS 类添加到 django RadioSelect 标签?

将 CSS 类添加到 django RadioSelect 标签

如何在 Flutter 小部件中测试回调函数

如何在 Django 中呈现单个单选按钮选项?

使用多个小部件进行委托

如何在Django管理员中制作单选按钮