代码之家  ›  专栏  ›  技术社区  ›  anonymous coward

Django ModelForm验证M2M的自定义自动完成功能,而不是丑陋的多重选择

  •  3
  • anonymous coward  · 技术社区  · 16 年前

    考虑到以下模型(为了理解而减少):

    class Venue(models.Model):
        name = models.CharField(unique=True)
    
    class Band(models.Model):
        name = models.CharField(unique=True)
    
    class Event(models.Model):    
        name = models.CharField(max_length=50, unique=True)       
        bands = models.ManyToManyField(Band) 
        venue = models.ForeignKey(Venue)
        start = models.DateField()
        end = models.DateField()
    

    管理区域对我所做的工作非常有用,但我想打开一点网站,以便某些用户可以添加新事件。对于公共部分,我在这些模型上有几个“管理”字段,我不希望公众看到这些字段(这很容易修复)。

    不过,我的具体问题是,在创建新事件时更改许多选择的显示。因为一个事件可以列出的带区数量不应该作为多选择框发送,所以我想使用处理多个带的自动完成功能(如标签框,StackOverflow上的此处!).

    我有这部分工作 ,它正确地用一个值的带区.id以逗号分隔来填充隐藏的输入。 然而 ,我无法理解如何组合起来让Django使用 模型形式 同时也验证了“乐队”的选择。

    理想情况下,我希望像StackOverflow上的标签那样自动完成,并以某种分隔字符串的形式发送所选的带区ID,同时让Django验证传递的带区是否存在,等等,就像我将烦人的多选择列表保留在适当的位置一样。

    我是否必须为窗体或模型创建自己的自动完成字段类型,并使用它?还有什么我忽略的吗?

    我已经看到一些现有的自动完成小部件,但我真的很喜欢使用我自己的自动完成代码,因为它已经设置好了,其中一些看起来有点复杂。

    这里有很多文本/解释,但我减少了,因为我避开了文本墙。如果我把重要的东西忘了,告诉我。

    2 回复  |  直到 16 年前
        1
  •  1
  •   tghw megawac    16 年前

    如果不知道你的自动完成代码在做什么,就有点难说了,但是只要它发送的是乐队的ID,就像它们将与 <select> 模型窗体应该像往常一样验证它们。

    基本上,您的post字符串应该如下所示:

    name=FooBar2009&bands=1&bands=3&bands=4&venue=7&start=...
    

    最简单的方法可能是使用javascript为用名称输入的每个波段添加(和删除)一个隐藏的输入字段。 band 带的ID作为值。然后,当用户提交表单时,浏览器将负责发布正确的内容,模型表单将对其进行验证。

        2
  •  0
  •   Skylar Saveland    16 年前

    使用注释的jquery自动完成插件,

    在客户端,我有这样的功能:

    jQuery("#id_tags").autocomplete('/tagging_utils/autocomplete/tasks/task/', {
        max: 10,
        highlight: false,
        multiple: true,
        multipleSeparator: " ",
        scroll: true,
        scrollHeight: 300,
        matchContains: true,
        autoFill: true,
    }); 
    

    所以,我有一个当我输入时返回的视图 a 以下内容:

    http://skyl.org/tagging_utils/autocomplete/tasks/task/?q=a&limit=10&timestamp=1259652876009

    您可以在这里看到服务于此的视图:

    http://github.com/skyl/skyl.org/blob/master/apps/tagging_utils/views.py

    现在,这会有点棘手……您可以将post排除在外,然后在字段的clean方法中,尝试基于字符串的.get()并在无法获取表单验证时引发错误…对,名称=…唯一=真的。所以有点像(从我的头顶上):

    def clean_bands(self):
        return Band.objects.filter( name__in = self.cleaned_data['bands'].split(' ') )
    

    您还可以检查每个字符串,如果没有该名称的带区,则会引发表单错误。不确定clean方法是否应返回qs。如果这有帮助,请告诉我,你希望我继续澄清。