【问题标题】:How to manually create a select field from a ModelForm in Django?如何从 Django 中的 ModelForm 手动创建选择字段?
【发布时间】:2012-04-23 09:22:09
【问题描述】:

我有一个ModelForm,其中一个字段(名为creator)是ForeignKey,所以对于{{ form.creator }},Django 会像这样呈现<select> 标签:

<select id="id_approver" name="approver">
    <option selected="selected" value="">---------</option>
    <option value="1">hobbes3</option>
    <option value="2">tareqmd</option>
    <option value="3">bob</option>
    <option value="4">sam</option>
    <option value="5">jane</option>
</select>

但我想添加一个onchange 事件属性,以便以后可以使用 AJAX 来做其他事情。我还想更改--------- 以说其他内容并显示批准者的全名,而不是他们的用户名。

那么是否可以获取可能的批准者列表并生成我自己的选择选项?有点像

<select id="id_approver" name="approver" onchange="some_ajax_function()">
    <option select="selected" value="0">Choose a user</option>
{% for approver in form.approver.all %} <!-- This won't work -->
    <option value="{{ approver.pk }}">{{ approver.get_full_name }}</option>
{% endfor %}
</select>

而且我还认为大多数审批者列表都太大(比如超过 50 个),然后我最终会想要审批者的某种可搜索的自动完成字段。那么我肯定需要编写自己的 HTML。

如果有人需要,我的ModelForm 如下所示:

class OrderCreateForm( ModelForm ) :
    class Meta :
        model = Order
        fields = (
            'creator',
            'approver',
            'work_type',
            'comment',
        )

【问题讨论】:

    标签: python django django-forms django-templates django-models


    【解决方案1】:

    ModelChoiceField documentation 解释了如何执行此操作。

    更改空标签:

    empty_label
    
        By default the <select> widget used by ModelChoiceField
        will have an empty choice at the top of the list. You can change the text
        of this label (which is "---------" by default) with the empty_label
        attribute, or you can disable the empty label entirely by setting
        empty_label to None:
    
        # A custom empty label
        field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)")
    
        # No empty label
        field2 = forms.ModelChoiceField(queryset=..., empty_label=None)
    

    至于您的第二个查询,文档中也有说明:

    The __unicode__ method of the model will be called to generate string
    representations of the objects for use in the field's choices;
    to provide customized representations, subclass ModelChoiceField and override
    label_from_instance. This method will receive a model object, and should return
    a string suitable for representing it. For example:
    
    class MyModelChoiceField(ModelChoiceField):
        def label_from_instance(self, obj):
            return "My Object #%i" % obj.id
    

    最后,要传递一些自定义 ajax,请为选择小部件使用 attrs 参数(在 ModelForm 字段中使用)。

    最后,你应该有这样的东西:

    creator = MyCustomField(queryset=...,
                            empty_label="Please select",
                            widget=forms.Select(attrs={'onchange':'some_ajax_function()'})
    

    【讨论】:

    • 所以对于上面的creator 示例,我必须从OrderCreateForm 中的fields 中删除creator,并为creator = MyCustomField(...) 添加您的代码行?还是我将creator 作为fields 列表的一部分(在class Meta 下)?
    • 您应该删除它,因为您使用自定义字段呈现它。
    • 我最终在模板中为creator 硬编码了&lt;select&gt;&lt;option&gt; 标签,因为我需要更复杂的creator 列表,它依赖于User。感谢您的回复,尽管如此!我仍然学到了一些东西:-)。
    • 你可以创建一个自定义渲染器(带有一个自定义小部件),它也会处理 HTML。
    • 那么creator 列表是动态的,取决于user.profile.user_type。我知道我可以在MyCustomField 中用queryset 更改creator 列表,但除非我可以将可选变量user_type 传递给class OrderCreateForm( ModelForm ),否则我将不得不创建5 个不同的(但大部分相同) OrderCreateForm.
    猜你喜欢
    • 2011-08-26
    • 1970-01-01
    • 2019-02-17
    • 2014-09-17
    • 2018-02-25
    • 2014-07-09
    • 2018-11-08
    • 2019-01-20
    • 2012-10-10
    相关资源
    最近更新 更多