Javascript Django:带有整数列表的表单

Javascript Django:带有整数列表的表单,javascript,django,forms,list,multiplechoicefield,Javascript,Django,Forms,List,Multiplechoicefield,我有一个javascript应用程序(angular)调用我的django应用程序。它使用整数列表来过滤响应。在Django中,我使用一个表单来清理数据 Javascript: app.factory('SearchData', function(){ return { shop:[], sort:'', xhr:'', brand

我有一个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端处理它。我不想使用multipleechoicefield,因为我需要在表单中提供选项(这会创建一个不必要的查询)。我要做的就是有一个整数列表

上面的表单抛出“输入一个整数”。我可以直接放弃表单,使用request.GET.getlist('shop')(这很有效)。但如果可能的话,我宁愿用表格

更新,现在我正在使用multipleechoicefield,并在视图中验证之前传递选择。比如:

shops = request.GET.getlist('shop', None)
sf = SearchForm(request.GET)
sf.fields['shop'].choices = shops

它可以工作,但并不漂亮。

使用自定义小部件/字段:

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数据将作为
repr
自身的第二次返回,即
['a','b']
返回为
[“['a','b']]”
,并在每次重新发布时进一步损坏

因此,我编写了以下函数,可用于在每次视图处理POST数据时修复损坏。这是一种攻击,因为它涉及使用私有变量使
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
用法(片段):


您可以使用
Django
forms
中的
TypedMultipleChoiceField
concurve=int
来避免对预定义选项列表进行验证,并覆盖
def valid\u值(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()

答案有点冗长,您可以将MultipleValueField和MultipleIntField组合到一个对象中,但效果非常好!当我找到这个答案时,我高兴得跳了起来,然后发现它被Django 1.11破坏了,或者可能是我把它推到了预期之外。不管怎么说,我发布了我作为答案得出的(黑客式)答案。(是的,我知道我来晚了,但这对其他人来说可能是一个有用的方法)也可以帮助人们了解
表单。Textinput可以被
表单取代。HiddenInput
(django 1.11)
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()