Django和ModelForm上的字段集
我知道你可以在django中为Admin助手指定字段集。 但是,我找不到对ModelForms有用的东西。 只是一些补丁,我不能使用。 我错过了什么吗? 有没有一种方法,我可以实现像字段集像没有手动写出我的模板上的每个字段在适当的标签。
我最好喜欢遍历一组BoundFields。 但是,在我的ModelForm结尾处做这样的事情:
fieldsets = [] fieldsets.append(('Personal Information', [username,password,password2,first_name,last_name,email]),) # add a 2 element tuple of string and list of fields fieldsets.append(('Terms & Conditions', [acceptterms,acceptprivacy]),) # add a 2 element tuple of string and list of fields
因为我的数据结构中包含的项目是原始字段,而不是BoundFields。 t看起来像BoundFields在飞行中生成…这让我难过。 我可以创build自己的forms.Form的子类,其中包含fieldset的概念(即使是粗糙的不向后兼容…这只是为我自己的项目),如果是这样,你可以给任何指针? 我不想乱django代码。
模型中的字段集仍处于“devise”阶段。 Django trac中有一个票价低的活动。
这是我近期研究自己感兴趣的事情,但是由于我还没有做到,所能提供的最好的是这些片段:
- 窗体分割/ Fieldset模板标签
- 分段表格
- 表单在字段集中分割
编辑:我只是再次注意到这个问题,我意识到它需要一个编辑指出卡尔的项目Django的forms实用程序,它包含一个BetterForm类可以包含字段集。 如果你喜欢这个项目,请给他一个+1的答案:)
我认为这个片段正是你想要的。 它为您提供了一个Form子类,允许您声明性地将表单细分为字段集,并在模板中遍历它们。
更新:该片段已成为django-form-utils的一部分
你可以做的一件事是把你的逻辑字段集分解成单独的模型表单类。
class PersonalInfoForm (forms.ModelForm): class Meta: model=MyModel fields=('field1', 'field2', ...) class TermsForm (forms.ModelForm): class Meta: model=MyModel fields=('fieldX', 'fieldY', ...)
通过不同的variables将它们传递给您的模板,并分解表单:
<form ...> <fieldset><legend>Personal Information</legend> {{ personal_info_form }} </fieldset> <fieldset><legend>Terms and Conditions</legend> {{ terms_form }} </fieldset> </form>
从这个意义上说,你的每个表单类只是实际的HTML表单的一个片段。
当您在窗体上调用保存时会引入一些复杂性。 你可能会想要传递commit = False,然后合并结果对象。 或者完全避免使用ModelForm.save,并手动使用'cleaned_data'来填充模型对象
Daniel Greenfelds django-uni-form通过布局帮助器类来解决这个问题。 我正在尝试它,它看起来很干净。
统一的助手可以使用布局对象。 布局可以由字段,行,列,HTML和字段组成 。
我原本selectDjango-uni-form,因为它符合第508条 。
这是我为了了解自定义标签而开发的代码(带有链接)。 我用它来创build一个fieldset。
免责声明:我鼓励使用上述任何答案,这只是为了学习。
templatetags/myextras.py
:
from django import template from django.template import Context register = template.Library() class FieldsetNode(template.Node): """ Fieldset renderer for 'fieldset' tag """ def __init__(self, nodelist, fieldset_name): """ Initialize renderer class https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#writing-the-renderer :param nodelist: a list of the template nodes inside a block of 'fieldset' :param fieldset_name: the name of the fieldset :return: None """ self.nodelist = nodelist self.fieldset_name = fieldset_name def render(self, context): """ Render the inside of a fieldset block based on template file https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#auto-escaping-considerations :param context: the previous template context :return: HTML string """ t = context.template.engine.get_template('myapp/fieldset.html') return t.render(Context({ 'var': self.nodelist.render(context), 'name': self.fieldset_name, }, autoescape=context.autoescape)) @register.tag def fieldset(parser, token): """ Compilation function for fieldset block tag Render a form fieldset https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#writing-the-compilation-function https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#parsing-until-another-block-tag :param parser: template parser :param token: tag name and variables :return: HTML string """ try: tag_name, fieldset_name = token.split_contents() except ValueError: raise template.TemplateSyntaxError("%r tag requires a single argument" % token.contents.split()[0]) if not (fieldset_name[0] == fieldset_name[-1] and fieldset_name[0] in ('"', "'")): raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name) nodelist = parser.parse(('endfieldset',)) parser.delete_first_token() return FieldsetNode(nodelist, fieldset_name[1:-1])
templates/myapp/fieldset.html
:
<div class="fieldset panel panel-default"> <div class="panel-heading">{{ name }}</div> <div class="panel-body">{{ var }}</div> </div>
templates/myapp/myform.html
:
<form action="{% url 'myapp:myurl' %}" method="post"> {% csrf_token %} {% fieldset 'General' %} {{form.myfield1 }} {% endfieldset %} {# my submit button #} </form>