Django 中的动态表单要求

Posted

技术标签:

【中文标题】Django 中的动态表单要求【英文标题】:Dynamic form requirements in Django 【发布时间】:2011-01-14 19:48:06 【问题描述】:

我即将在工作中启动一个大型 Django 项目。关键功能是表单处理。该应用程序的用户将使用很多表格。一个要求是应该可以在应用程序的管理界面中编辑表单。

也就是说,添加/删除表单字段不是必需的。但是应该可以编辑表单字段属性。例如,更改哪些字段是必需的等等。

对于如何做到这一点,任何人都有任何好的解决方案。我在想我可能必须对我想要动态的字段进行子类化并在那里做一些事情。我想所有模型字段都必须具有“空白=真/空=真”,并且一些如何在单独的模型中添加一些元信息(?)关于声明哪些字段是必需的模型的。然后在显示和验证表单时使用该信息。

在我开始这样做之前,我真的很想就如何设计这样一个解决方案提供一些意见,有人知道应该如何做吗?


经过更多研究,我了解到您可以使用工厂函数做很多事情,这些函数将返回具有给定属性集的表单。所以看起来这个问题并不难解决。

我会创建一个函数来返回一个带有正确属性/字段集的表单。但是我还没有找到一个好的解决方案的部分是如何在管理界面中管理它。我在想我会制作一个 db.Model 来存储有关另一个模型字段的信息。我可以在哪里设置哪些是必需的等等。

然后在返回表单的函数中,通过该模型并返回具有正确属性的表单。但是如何以一种好的方式制作该模型(应该反映另一个模型的字段)?

【问题讨论】:

【参考方案1】:

您应该为此使用某些模型。对于可能以这种方式定制的每个表单,都必须创建一个新的数据库条目。我想,它应该是这样的:

class FormSettings(Model):
  form = CharField(..)

class FormAttrib(Model):
  form_settings = ForeignKey(FormSettings)
  field = CharField(..)
  attrib_name=CharField(..)
  attrib_value=CharField(..)

在 FormSettings.form 中,您应该存储一些表单地址,例如 .并且在构建表单时(在 init 中),它应该在 db 中查找条目并使用为其描述的属性。

如果您为表单使用自己的元类并使其在数据库中注册(创建适当的 FormSettings 条目),则可以在创建类时轻松创建数据库条目。进程启动时会做一次,应该没那么糟糕。

希望对你有一点帮助。如果您还有其他问题,我很乐意提供帮助 :-) 我喜欢 django 的那些非标准设备 :-) 这就是所有乐趣的开始:-)

编辑:

好的,假设您希望拥有应用程序食物并使用 food_name 字段形成 FavouriteFoodForm。您将 formsettings 表中的数据库存储为 food.FavouriteFoodForm 并添加一个属性设置:field='food_name', attrib_name='required', attribute_value='True'(它并不完美,但仍然没有那么糟糕')。

在 FavouriteFoddForm 中没有你在数据库中查找设置,所以你这样做:

settings = FormSettings.objects.get(form=app_name + self.__class__.name)

然后你迭代设置

for setting in settings.formattrib_set():

在这里你可以简单地调用 exec 并设置适当的属性:

exec("getattr(self, settings.field)[attrib_name] = %s" % attrib_value)

这应该将属性设置为 required=True。

【讨论】:

感谢您的回复,但我在理解您的意思时遇到了一些问题。您能否为您的解决方案写一个更详细的描述?就像我在问题的最后一部分中提到的那样,我在 b-list.org b-list.org/weblog/2008/nov/09/dynamic-forms 的这篇文章中找到了很多有用的信息,似乎这会很有帮助。但仍然需要解决如何将表单设置存储在 db 中。 好的,这对我来说更有意义。似乎是一个可行的解决方案。但是可以做得更优雅吗?是否可以进行模型自省或填充 FormAttrib 和 FormSettings 的东西? 你的意思是Form introspection,对吧?是的,它可以做到,但我相信,这里描述的有点太多了 ;) 尝试阅读元类 - 我相信这是你需要它们的重点,尽管一些 python 大师说,在 99%您不需要它们的情况。最好阅读 ModelForm 的代码,它会分析模型以构建适当的字段。您将需要类似的东西,但对于 Form。基本上,你会用另一种方式来做,并有 FormModel ;-)【参考方案2】:

这不是您问题的确切答案,但我做了类似的事情,我认为可能对您有用。我创建了一个完全可自定义的表单,以便最终用户可以自定义表单。

我最终得到了 2 个模型,一个 BuiltForm 和一个 BuiltFormField

class BuiltForm(models.Model): 
    name = models.CharField(max_length=32) 
    def form(self, data=None, initial=None):
        form = BuiltFormGenericForm(data, initial=initial)
        form.addBuiltFormFields(BuiltFormField.objects.filter(builtform=self, disabled=0))
        return form            

class BuiltFormField(models.Model):
    builtform = models.ForeignKey(BuiltForm)
    type = models.CharField(max_length=32, choices=ALL_FIELD_TYPES)
    label = models.CharField(max_length=32)
    fieldname = models.CharField(max_length=32)
    helptext = models.CharField(max_length=256, blank=True)
    required = models.BooleanField(default=False)
    sort_order = models.IntegerField(default=0)
    disabled = models.BooleanField(default=False)
    options = models.TextField(blank=True)
    def field(self):
        field = ALL_FIELD_MAPS.get(self.type)
        ## Build out the field, supplying choices, `required`, etc.

有几件事是不正常的。 ALL_FIELD_TYPES 是表单中允许的字段类型的映射。这与dict() 结合使用,以识别该字段应使用哪个类(CharFieldEmailFieldChoiceField 等)。 options 也是 pickled 选项列表,供以后在 ChoiceField 中使用。这使我可以创建任意选项列表,而无需单独调用数据库。

另一个主要部分是自定义Form 类,它允许使用BuiltForm 中的字段填充自身。我的看起来像这样:

class BuiltFormGenericForm(forms.Form):
    built_form_fields = 
    builtform = None
    def addBuiltFormFields(self, fields):
        for field in fields:
            self.fields[field.label] = field.field()
            self.built_form_fields[field.pk] = field
    def is_valid(self):
        # Do validation here.  My code for this is pretty big because of custom fields
        # and calculations that I have to squeeze in.

BuiltFormField 对象并非设计为通过管理界面创建,而是通过使用大量 javascript 的自定义对象创建,以使其对用户友好,但您当然可以公开 BuiltFormField 模型的部分内容在管理界面中进行更新。

希望这可以帮助您为表单制定模型。

【讨论】:

天才,这里有很多很棒的代码和概念。很高兴看到这样的事情是可能的。类似于@gruszczy 提出的解决方案。

以上是关于Django 中的动态表单要求的主要内容,如果未能解决你的问题,请参考以下文章

Django 表单字段动态显示

如何根据用户输入动态更改 django 中的表单(提交前)

django - 表单中的动态选择字段

Django:如何添加动态类以选择表单中的选项

Django 动态表单,带有 HTML 数组的表单集

Django:在表单向导中为步骤动态设置表单集