Foo*_*oon 19 django django-forms
我正在寻找的东西:一个小工具,为用户提供一个下拉选项列表,但后面还有一个文本输入框,供用户输入新值.
后端模型将具有一组默认选项(但不会在模型上使用choices关键字).我知道我可以(并且我已经)通过让表单同时具有ChoicesField和CharField来实现这一点,并且如果ChoicesField保留默认值,则代码使用CharField,但这感觉"un-django"就像.
是否有一种方法(使用Django-builtins或Django插件)来定义类似ChoiceEntryField(在IIRC为此进行模拟的GtkComboboxEntry之后)?
如果有人发现这一点,请注意,从UX角度来看,如何最好地完成我正在寻找的内容存在类似的问题,请访问https://ux.stackexchange.com/questions/85980/is-there-a-ux-图案换下拉优选的-丁自由文本允许的
小智 27
我建议使用自定义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)
Run Code Online (Sandbox Code Playgroud)
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')
Run Code Online (Sandbox Code Playgroud)
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
})
Run Code Online (Sandbox Code Playgroud)
我知道我有点迟到了,但我最近使用了另一个解决方案.
我使用了带有参数的django-floppyformsInput小部件.这将生成一个HTML5 元素,您的浏览器会自动创建一个建议列表(另请参阅此SO答案).datalist<datalist>
以下是模型表单的简单外观:
class MyProjectForm(ModelForm):
class Meta:
model = MyProject
fields = "__all__"
widgets = {
'name': floppyforms.widgets.Input(datalist=_get_all_proj_names())
}
Run Code Online (Sandbox Code Playgroud)
编辑:更新以使其也适用于 UpdateView
所以我正在寻找的似乎是
工具.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]
Run Code Online (Sandbox Code Playgroud)
(表单.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
Run Code Online (Sandbox Code Playgroud)
(示例虚拟模型.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})
Run Code Online (Sandbox Code Playgroud)
(样品哑views.py: )
from .forms import DemoForm
from .models import Dummy
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView
class DemoCreateView(CreateView):
form_class = DemoForm
model = Dummy
class DemoUpdateView(UpdateView):
form_class = DemoForm
model = Dummy
class DemoDetailView(DetailView):
model = Dummy
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16358 次 |
| 最近记录: |