一尘不染

Django形式有选择,但也有自由文本选项?

django

我要寻找的是:单个小部件,它为用户提供了一个下拉选择列表,然后在其下方还有一个文本输入框,供用户输入新值。

后端模型将具有一组默认选项(但不会在模型上使用choices关键字)。我知道我可以(并且已经实现)通过将表单同时具有ChoicesField和CharField来实现这一点,并且如果ChoicesField保留为默认值,则代码可以使用CharField,但这感觉像“ un-django”。

有没有一种方法(使用Django-builtins或Django插件)为表单定义类似ChoiceEntryField(模仿IIRC的GtkComboboxEntry建模)的方法?


阅读 328

收藏
2020-04-02

共1个答案

一尘不染

我会推荐一种自定义的Widget方法,HTML5允许你使用带有下拉列表的自由文本输入,该下拉列表可以用作“一键通”或“另一写”类型的字段,这就是我的方法:

fields.py

from django import forms

class ListTextWidget(forms.TextInput):
    def __init__(self, data_list, name, *args, **kwargs):
        super(ListTextWidget, self).__init__(*args, **kwargs)
        self._name = name
        self._list = data_list
        self.attrs.update({'list':'list__%s' % self._name})

    def render(self, name, value, attrs=None, renderer=None):
        text_html = super(ListTextWidget, self).render(name, value, attrs=attrs)
        data_list = '<datalist id="list__%s">' % self._name
        for item in self._list:
            data_list += '<option value="%s">' % item
        data_list += '</datalist>'

        return (text_html + data_list)

forms.py

from django import forms
from myapp.fields import ListTextWidget

class FormForm(forms.Form):
   char_field_with_list = forms.CharField(required=True)

   def __init__(self, *args, **kwargs):
      _country_list = kwargs.pop('data_list', None)
      super(FormForm, self).__init__(*args, **kwargs)

    # the "name" parameter will allow you to use the same widget more than once in the same
    # form, not setting this parameter differently will cuse all inputs display the
    # same list.
       self.fields['char_field_with_list'].widget = ListTextWidget(data_list=_country_list, name='country-list')

views.py

from myapp.forms import FormForm

def country_form(request):
    # instead of hardcoding a list you could make a query of a model, as long as
    # it has a __str__() method you should be able to display it.
    country_list = ('Mexico', 'USA', 'China', 'France')
    form = FormForm(data_list=country_list)

    return render(request, 'my_app/country-form.html', {
        'form': form
    })
2020-04-02