我正在寻找的内容:一个单一的小部件,它为用户提供下拉选择列表,然后在其下方还有一个文本输入框,供用户输入新值。
后端模型将具有一组默认选项(但不会在模型上使用choices关键字)。我知道我可以(并且已经实现)通过将表单同时具有ChoicesField和CharField来实现这一点,并且如果ChoicesField保留为默认值,则代码可以使用CharField,但这感觉就像“ un-django”一样。
是否有一种方法(使用Django-builtins或Django插件)为表单定义类似ChoiceEntryField(模仿IIRC的GtkComboboxEntry建模)?
[如果有人发现此问题,请注意,在https://ux.stackexchange.com/questions/85980/is-there-a-ux-pattern-for-drop-down-preferred-but-free-text-allowed,从UX角度来看,如何最好地完成我所寻找的问题,存在类似的问题
我会推荐一种自定义的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
})
我知道我参加聚会有点晚了,但是我最近使用了另一种解决方案。
我已将Input
widget的Input
与django-floppyforms参数一起使用。这将生成HTML5 datalist
元素,您的浏览器会为此元素自动创建建议列表(另请参见<datalist>
)。
这就是模型表格的外观:
this SO answer
编辑:已更新,使其也可以与UpdateView一起使用
所以我要找的似乎是
utils.py:
class MyProjectForm(ModelForm):
class Meta:
model = MyProject
fields = "__all__"
widgets = {
'name': floppyforms.widgets.Input(datalist=_get_all_proj_names())
}
(forms.py)
from django.core.exceptions import ValidationError
from django import forms
class OptionalChoiceWidget(forms.MultiWidget):
def decompress(self,value):
#this might need to be tweaked if the name of a choice != value of a choice
if value: #indicates we have a updating object versus new one
if value in [x[0] for x in self.widgets[0].choices]:
return [value,""] # make it set the pulldown to choice
else:
return ["",value] # keep pulldown to blank, set freetext
return ["",""] # default for new object
class OptionalChoiceField(forms.MultiValueField):
def __init__(self, choices, max_length=80, *args, **kwargs):
""" sets the two fields as not required but will enforce that (at least) one is set in compress """
fields = (forms.ChoiceField(choices=choices,required=False),
forms.CharField(required=False))
self.widget = OptionalChoiceWidget(widgets=[f.widget for f in fields])
super(OptionalChoiceField,self).__init__(required=False,fields=fields,*args,**kwargs)
def compress(self,data_list):
""" return the choicefield value if selected or charfield value (if both empty, will throw exception """
if not data_list:
raise ValidationError('Need to select choice or enter text for this field')
return data_list[0] or data_list[1]
(样本虚拟模型.py] ::]
)from .utils import OptionalChoiceField from django import forms from .models import Dummy class DemoForm(forms.ModelForm): name = OptionalChoiceField(choices=(("","-----"),("1","1"),("2","2"))) value = forms.CharField(max_length=100) class Meta: model = Dummy
(示例虚拟views.py:
from django.db import models
from django.core.urlresolvers import reverse
class Dummy(models.Model):
name = models.CharField(max_length=80)
value = models.CharField(max_length=100)
def get_absolute_url(self):
return reverse('dummy-detail', kwargs={'pk': self.pk})
我的要求与OP相似,但基本字段为DecimalField
在选择字段和文本字段中输入类型是否相同?如果是这样,我将在类中创建一个CharField(或Textfield),并通过应用“如果下拉列表中没有信息,请在textfield中使用数据”子句让一些前端javascript / jquery负责传递哪些数据。 >
我做了一个class FrequencyDataForm(ModelForm):
frequency_measurement = DecimalOptionsField(
choices=(
('Low Freq', (
('11.11', None),
('22.22', None),
(33.33, None),
),
),
('High Freq', (
('66.0E+06', None),
(1.2E+09, None),
('2.4e+09', None)
),
)
),
required=False,
max_digits=15,
decimal_places=3,
)
class Meta:
model = FrequencyData
fields = '__all__'
,以演示如何在前端进行此操作。
这是我解决此问题的方式。我从传递给模板var txt = document.getElementById('txtbox');
var btn = document.getElementById('inputbutton');
txt.disabled=true;
$(document).ready(function() {
$('#dropdown1').change(function() {
if($(this).val() == "Three"){
document.getElementById('txtbox').disabled=false;
}
else{
document.getElementById('txtbox').disabled=true;
}
});
});
btn.onclick = function () {
if((txt).disabled){
alert('input is: ' + $('#dropdown1').val());
}
else{
alert('input is: ' + $(txt).val());
}
};
对象的位置检索选项,然后手动填充form
:
我知道这很旧,但认为这可能对其他人有用。以下实现与{% for field in form %}
<div class="form-group">
{{ field.label_tag }}
<input list="options" name="test-field" required="" class="form-control" id="test-field-add">
<datalist id="options">
{% for option in field.subwidgets %}
<option value="{{ option.choice_label }}"/>
{% endfor %}
</datalist>
</div>
{% endfor %}
答案类似的结果,但适用于使用django本机方法的模型,查询集和外键。
参加聚会晚了5年,但是@Foon的自我回答from .fields import *
from django import forms
Class ListTxtForm(forms.Form):
field = ChoiceTxtField(queryset=YourModel.objects.all()) # Using new field
field2 = ModelChoiceField(queryset=YourModel.objects.all(),
widget=ListTextWidget()) # Using Widget
正是我想要的,希望其他想问相同问题的人可以像我以前一样被此处的StackOverflow的答案寻找算法指导。