Django:带有整数列表的表单
Django: Form with list of integers
我有一个 javascript 应用程序(在 angular 中)调用我的 django 应用程序。它使用整数列表来过滤响应。在 Django 中,我使用表单来清理数据。
Javascript:
app.factory('SearchData',
function(){
return {
shop:[],
sort:'',
xhr:'',
brand:[],
};
});
app.factory('SearchQuery',
['$http', '$location', '$route', 'SearchData',
function($http, $location, $route, SearchData){
return {
getItems: function(){
return $http.get('/search/',{
params: SearchData,
responseType: 'json',
});
}
};
}
]);
Python形式:
class SearchForm(forms.Form):
shop = forms.IntegerField(widget=forms.SelectMultiple(),required=False)
sort = forms.CharField(max_length=1, min_length=1, required=False)
brand = forms.IntegerField(widget=forms.SelectMultiple(),required=False)
我在商店和品牌中得到了一个整数列表,但我不知道如何在 Django 端处理它。我不想使用 MultipleChoiceField,因为我需要以形式提供选择(这会创建不必要的查询)。我想要做的就是有一个整数列表。
上面的表格抛出 "Enter a whole number."。我可以放弃表格并使用 request.GET.getlist('shop') (有效)。但如果可能的话,我宁愿使用表格...
更新,现在我正在使用 MultipleChoiceField 并在视图中验证之前传递选择。喜欢:
shops = request.GET.getlist('shop', None)
sf = SearchForm(request.GET)
sf.fields['shop'].choices = shops
可以用,但不够漂亮。
使用自定义 widget/field:
from django import forms
from django.core.exceptions import ValidationError
class MultipleValueWidget(forms.TextInput):
def value_from_datadict(self, data, files, name):
return data.getlist(name)
class MultipleValueField(forms.Field):
widget = MultipleValueWidget
def clean_int(x):
try:
return int(x)
except ValueError:
raise ValidationError("Cannot convert to integer: {}".format(repr(x)))
class MultipleIntField(MultipleValueField):
def clean(self, value):
return [clean_int(x) for x in value]
class SearchForm(forms.Form):
shop = MultipleIntField()
Udi 的代码很好,但如果您想将其用作(比方说)完全通用的用户输入表单的隐藏字段,则存在问题(在 Django 1.11.7 下)。问题是,如果用户输入验证失败并重新 POST 进行更正,则多值 POST 数据会作为自身的 repr
第二次返回, IE
['a','b']
以 ["['a', 'b']"]
的形式返回,并随着每个重新 POST
的进一步破坏
所以我写了下面的函数,可以用来修复每次视图处理POST数据时的损坏。这是一个 hack,因为它涉及使用私有变量使 request.POST
临时可变。它也不能正确处理包含逗号、转义引号等的字符串列表。
def sanitize_keys( request, only=None):
""" Restore multi-valued keys that have been re-posted. there's a repr
in the round trip, somewhere.
only = list of keys to sanitize. Default is all of them."""
mutt = request.POST._mutable
request.POST._mutable = True
keylist = only or request.POST.keys()
for key in keylist:
v = request.POST.get(key)
if v.startswith("[") and v.endswith("]"):
#print( "Debug: sanitizing " + v )
sanitized=[]
for s in v[1:-1].split(','):
s = s.strip()
if s.startswith("'") and s.endswith("'"):
s=s[1:-1].replace("\'","'")
sanitized.append(s)
#print( "Debug: sanitized= ", sanitized )
request.POST.setlist( key, sanitized)
request.POST._mutable = mutt
return
用法(片段):
class TestForm( forms.Form):
name = forms.CharField()
...
customer_iid = MultipleValueField( required=False)
...
# POST
sanitize_keys( request, only=('customer_iid',) )
#print( 'Debug: customer_iid', request.POST.getlist('customer_iid', []) )
form = TestForm( request.POST)
您可以将 Django
forms
中的 TypedMultipleChoiceField
与 coerce=int
一起使用,并避免根据预定义的选项列表进行验证,覆盖 def valid_value(self, value):
方法:
class MultipleIntegersField(forms.TypedMultipleChoiceField):
def __init__(self, *args, **kwargs):
super(MultipleIntegersField, self).__init__(*args, **kwargs)
self.coerce = int
def valid_value(self, value):
return True
class SearchForm(forms.Form):
shop = MultipleIntegersField()
我有一个 javascript 应用程序(在 angular 中)调用我的 django 应用程序。它使用整数列表来过滤响应。在 Django 中,我使用表单来清理数据。
Javascript:
app.factory('SearchData',
function(){
return {
shop:[],
sort:'',
xhr:'',
brand:[],
};
});
app.factory('SearchQuery',
['$http', '$location', '$route', 'SearchData',
function($http, $location, $route, SearchData){
return {
getItems: function(){
return $http.get('/search/',{
params: SearchData,
responseType: 'json',
});
}
};
}
]);
Python形式:
class SearchForm(forms.Form):
shop = forms.IntegerField(widget=forms.SelectMultiple(),required=False)
sort = forms.CharField(max_length=1, min_length=1, required=False)
brand = forms.IntegerField(widget=forms.SelectMultiple(),required=False)
我在商店和品牌中得到了一个整数列表,但我不知道如何在 Django 端处理它。我不想使用 MultipleChoiceField,因为我需要以形式提供选择(这会创建不必要的查询)。我想要做的就是有一个整数列表。
上面的表格抛出 "Enter a whole number."。我可以放弃表格并使用 request.GET.getlist('shop') (有效)。但如果可能的话,我宁愿使用表格...
更新,现在我正在使用 MultipleChoiceField 并在视图中验证之前传递选择。喜欢:
shops = request.GET.getlist('shop', None)
sf = SearchForm(request.GET)
sf.fields['shop'].choices = shops
可以用,但不够漂亮。
使用自定义 widget/field:
from django import forms
from django.core.exceptions import ValidationError
class MultipleValueWidget(forms.TextInput):
def value_from_datadict(self, data, files, name):
return data.getlist(name)
class MultipleValueField(forms.Field):
widget = MultipleValueWidget
def clean_int(x):
try:
return int(x)
except ValueError:
raise ValidationError("Cannot convert to integer: {}".format(repr(x)))
class MultipleIntField(MultipleValueField):
def clean(self, value):
return [clean_int(x) for x in value]
class SearchForm(forms.Form):
shop = MultipleIntField()
Udi 的代码很好,但如果您想将其用作(比方说)完全通用的用户输入表单的隐藏字段,则存在问题(在 Django 1.11.7 下)。问题是,如果用户输入验证失败并重新 POST 进行更正,则多值 POST 数据会作为自身的 repr
第二次返回, IE
['a','b']
以 ["['a', 'b']"]
的形式返回,并随着每个重新 POST
所以我写了下面的函数,可以用来修复每次视图处理POST数据时的损坏。这是一个 hack,因为它涉及使用私有变量使 request.POST
临时可变。它也不能正确处理包含逗号、转义引号等的字符串列表。
def sanitize_keys( request, only=None):
""" Restore multi-valued keys that have been re-posted. there's a repr
in the round trip, somewhere.
only = list of keys to sanitize. Default is all of them."""
mutt = request.POST._mutable
request.POST._mutable = True
keylist = only or request.POST.keys()
for key in keylist:
v = request.POST.get(key)
if v.startswith("[") and v.endswith("]"):
#print( "Debug: sanitizing " + v )
sanitized=[]
for s in v[1:-1].split(','):
s = s.strip()
if s.startswith("'") and s.endswith("'"):
s=s[1:-1].replace("\'","'")
sanitized.append(s)
#print( "Debug: sanitized= ", sanitized )
request.POST.setlist( key, sanitized)
request.POST._mutable = mutt
return
用法(片段):
class TestForm( forms.Form):
name = forms.CharField()
...
customer_iid = MultipleValueField( required=False)
...
# POST
sanitize_keys( request, only=('customer_iid',) )
#print( 'Debug: customer_iid', request.POST.getlist('customer_iid', []) )
form = TestForm( request.POST)
您可以将 Django
forms
中的 TypedMultipleChoiceField
与 coerce=int
一起使用,并避免根据预定义的选项列表进行验证,覆盖 def valid_value(self, value):
方法:
class MultipleIntegersField(forms.TypedMultipleChoiceField):
def __init__(self, *args, **kwargs):
super(MultipleIntegersField, self).__init__(*args, **kwargs)
self.coerce = int
def valid_value(self, value):
return True
class SearchForm(forms.Form):
shop = MultipleIntegersField()