【问题标题】:Django form to indicate input type用于指示输入类型的 Django 表单
【发布时间】:2015-10-10 20:45:32
【问题描述】:

另一个我很担心的基本问题。我浏览过各种 Django 文档页面,也搜索过这个站点。我在这里发现的唯一内容是在 2013 年,它建议设置自定义过滤器模板。

无论如何,我正在尝试生成自己的表单,而不是使用 Django 自己的方式通过 {{ form }} 生成它。这只是为了让我可以控制表单的呈现方式。

我已经制定了各种访问所需信息的方法,例如(在我的 for item in form 循环中);

  • item.help_text
  • item.label_tag
  • item.id_for_label

我正在尝试识别项目类型,以便我可以使用正确的输入类型,但是我正在努力确定 item.xxxx 应该是什么。由于这是通过 {{ form }} 正确显示的,我假设此信息在表单中的某处可用,只是努力找出如何访问它,以便我可以识别正确的输入类型。我正在手动执行此操作,因此我可以使用正确的 Bootstrap 样式来显示输入字段。

任何帮助将不胜感激(或只是指出正确的方向)。我对此很陌生,因此为我的非常基本的问题道歉,如果不认识我可以去问这些问题的人,这很困难。

问候

韦恩

不确定你是否需要它,但这里有一些代码;

表格:

class NewsForm(ModelForm):
    class Meta:
        model = News_Article
        exclude = ('news_datetime_submitted', 'news_yearmonth', )
        labels = {
            'news_title': _('Enter News Title'),
        }
        help_texts = {
            'news_title': _('Enter a title to give a short description of what the news is.'),
        }
        error_messages = {
            'news_title': {
                'max_length': _("News title is too long."),
            },
        }

查看(尚未在 POST 上工作,这只是 Django 文档中的内容,POST 是我接下来要解决的问题)

def create(request, dataset):
    if dataset not in ['news', 'announcement']:
        return HttpResponseRedirect(reverse('pages'))
    rDict = {}
    if request.method == 'POST':
        if dataset == "news":
            form = NewsForm(request.POST)
        elif dataset == "announcement":
            form = AnnouncementForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/home/')
        else:
            pass
    else:
        announcement = get_announcement()
        if not announcement == None:
            rDict['announcement'] = announcement
        if dataset == "news":
            rDict['form'] = NewsForm()
            rDict['branding'] = {'heading': 'Create News Item', 'breadcrumb': 'Create News', 'dataset': 'create/' + dataset + '/'}
        elif dataset == "announcement":
            rDict['form'] = AnnouncementForm()
            rDict['branding'] = {'heading': 'Create Announcement', 'breadcrumb': 'Create Announcement', 'dataset': 'create/' + dataset + '/'}
        rDict['sitenav'] = clean_url(request.path, ['"', "'"])
        rDict['menu'] = Menu.objects.all().order_by('menu_position')
#        pdb.set_trace()
        return render(request, 'en/public/admin/admin_create.html', rDict)

模板代码

<form action="/siteadmin/{{ branding.dataset }}" method="post">
    {% csrf_token %}
    {% for item in form %}
        <div class="row">
            <div class="col-xs-2 col-md-2">
            </div>
            <div class="col-xs-4 col-md-4">
                <div class="panel-title pull-right">
                    {% if item.help_text %}
                      <img src="/static/images/info.png" height="20" width="20" aria-hidden="true" data-toggle="popover" title="{{ item.help_text }}">&nbsp
                    {% endif %}
                    {{ item.label_tag }}
                </div>
            </div>
            <div class="col-xs-4 col-md-4">
                <div class="input-group">       
                    <input type="{{ item.widget }}" class="form-control" placeholder="" aria-describedby="{{ item.id_for_label }}">
                </div>
            </div>
            <div class="col-xs-2 col-md-2">
                {% if forloop.last %}
                    <input type="submit" value="Submit" />
                {% endif %}
            </div>          
        </div>
    {% endfor %}
</form>

【问题讨论】:

    标签: python django forms django-forms


    【解决方案1】:

    试试这个:

    <input type="{{ item.field.widget.input_type }}" ...
    

    没有文档链接,使用调试器找到了它(我知道这不是最佳实践...)

    根据@Smurf 的评论,这不适用于所有小部件,例如 SelectCheckBox、任何 MultiWidget 等...似乎仅适用于文本输入及其变体(密码、电子邮件...)


    更好的解决方案是创建自定义小部件并像往常一样在模板中呈现表单字段。您可以在那里设置任何自定义属性,请参阅https://docs.djangoproject.com/en/1.8/ref/forms/widgets/#customizing-widget-instances


    如果您必须修改模板中的小部件,请使用django-widget-tweaks

    这个应用程序提供了一个漂亮的表单过滤器来改变小部件(即它们的属性)。但请注意,它是通过对已渲染的 HTML 进行字符串贩卖(“渲染”与 Widget 实例相关)来实现的。

    【讨论】:

    • 请不要使用这个 - 这不会出现在所有 Widget 类型上。例如,它不会出现在Select 小部件上。创建自定义小部件是正确的答案。
    • 再次感谢@frnhr 的回复。有趣的是,CheckBox 似乎不起作用。 Item.field.widget 将 CheckBox 项目列为
    • 感谢 DanielB。注意到。如果我使用模型创建表单,您是否有指向创建自定义小部件的操作指南的链接。除非我误解了 Django 指南中的某些内容,否则在从头开始创建表单时会创建自定义小部件。对于我目前正在做的项目,手动操作并没有太大问题,但我的下一个项目将有很多表单字段。谢谢,韦恩
    • @Daniel Roseman 给出的答案应该对您有用,如果您仍然需要创建自定义小部件,您可以像使用 labelshelp_texts 一样使用 widgets 属性, ... 在Meta 类中。
    • @Smurf 请参阅我的答案中的链接,它准确显示了如何向小部件添加属性。
    【解决方案2】:

    这是错误的做法。您在此处所做的自定义都是针对输入属性的,这些都在表单类本身中完成。

    class NewsForm(ModelForm):
        news_title = forms.CharField(widget=forms.TextInput(
            attrs={'class': 'form-control', 'placeholder': 'whatever', label: ('Enter News Title')})
    

    现在你可以这样做了:

    <div class="input-group">       
        {{ item }}
    </div>
    

    编辑

    如果不想重新定义每个字段,可以直接在 Meta 类中设置小部件:

    class Meta:
        model = News_Article
        widgets = {
            'news_title': forms.TextInput(attrs={'class': 'form-control'})
        }
    

    如果重复太多,可以直接在表单的__init__方法中修改属性:

    class NewsForm(ModelForm):
        def __init__(self, *args, **kwargs)
            super(NewsForm, self).__init__(*args, **kwargs)
            for field in self.fields.values():
                field.widget.attrs['class'] = 'form-control'
    

    【讨论】:

    • 感谢丹尼尔-罗斯曼的回复。我确实考虑过这样做,但是这不允许您将表单基于模型,这就是我在上面所做的。令人沮丧的是,Django 没有提供必要的属性来更轻松地手动创建表单(即,我发现无法检测该字段的输入类型,因此我可以更多地自定义我的输入类型。
    • 我不明白你的评论。这绝对基于模型;您唯一要做的就是覆盖 news_title 字段。您甚至可以通过在 Meta 类中定义 widgets 字典来自定义小部件本身。
    • 对不起丹尼尔,我把自己弄糊涂了。您的班级不是为 NewsForm 手动创建表单字段吗?这就是我重播的意思。我的 Meta: model = News_Article 类,所以我不需要定义每个字段和数据类型。使用已经定义的模型时我做的不对吗?
    猜你喜欢
    • 2021-05-09
    • 2019-11-26
    • 1970-01-01
    • 2022-10-25
    • 2023-01-19
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多