ModelForm 上的 Django 和字段集

发布于 2024-07-14 00:29:54 字数 780 浏览 7 评论 0原文

我知道您可以在 django 中为管理助手指定字段集。 但是,我找不到任何对 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。 看起来 BoundFields 是动态生成的......这让我很难过。 我可以创建自己的 forms.Form 子类,其中包含字段集的概念(即使是一个不向后兼容的粗略的子类......这仅适用于我自己的项目),如果是这样,您能给出任何指针吗? 我不想弄乱 django 代码。

I know you can specify fieldsets in django for Admin helpers. However, I cannot find anything useful for ModelForms. Just some patches which I cannot use. Am I missing something? Is there a way I could achieve something like fieldsets without manually writing out each field on my template in the appropriate tag.

I would ideally like to iterate through a set of BoundFields. However, doing something like this at the end of my 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

fails as the items contained in my data structure are the raw fields, not the BoundFields. t looks like BoundFields are generated on the fly... this makes me sad. Could I create my own subclass of forms.Form which contains a concept of fieldsets (even a rough one that is not backward compatible... this is just for my own project) and if so, can you give any pointer? I do not want to mess with the django code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

半岛未凉 2024-07-21 00:29:54

我认为 此片段 正是您想要的。 它为您提供了一个 Form 子类,允许您以声明方式将表单细分为字段集并在模板中迭代它们。

更新:该片段已成为 django-form-utils 的一部分

I think this snippet does exactly what you want. It gives you a Form subclass that allows you to declaratively subdivide your form into fieldsets and iterate through them in your template.

Update: that snippet has since become part of django-form-utils

落在眉间の轻吻 2024-07-21 00:29:54

模型表单中的字段集仍处于“设计”阶段。 Django trac 中有一张ticket,活动量较低。

这是我在不久的将来有兴趣研究自己的事情,但由于我还没有这样做,所以我能提供的最好的就是这些片段:

编辑: 我刚刚再次注意到这个问题,我意识到需要进行编辑来指出 Carl 的项目 django-form-utils其中包含一个 BetterForm 类,该类可以包含字段集。 如果您喜欢这个项目,请为他的下面的答案+1 :)

Fieldsets in modelforms are still in "design" stage. There's a ticket in Django trac with low activity.

It's something I've been interested in researching myself in the near future, but since I haven't done it yet the best I can offer are these snippets:

Edit: I just noticed this question again and I realize it needs an edit to point out Carl's project django-form-utils which contains a BetterForm class which can contain fieldsets. If you like this project give him a +1 for his answer below :)

牛↙奶布丁 2024-07-21 00:29:54

您可以做的一件事是将逻辑字段集分解为单独的模型表单类。

class PersonalInfoForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('field1', 'field2', ...)

class TermsForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('fieldX', 'fieldY', ...)

将它们通过不同的变量传递给模板并分解表单集:

<form ...>
   <fieldset><legend>Personal Information</legend>
       {{ personal_info_form }}
   </fieldset>
   <fieldset><legend>Terms and Conditions</legend>
       {{ terms_form }}
   </fieldset>
</form>

从这个意义上说,每个表单类只是实际 HTML 表单的一个片段。

当您在表单上调用 save 时,它​​会带来一定的复杂性。 您可能需要传递 commit=False ,然后合并生成的对象。 或者完全避免使用 ModelForm.save 并使用“cleaned_data”手动填充模型对象

One thing you can do is break your logical fieldsets into separate model form classes.

class PersonalInfoForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('field1', 'field2', ...)

class TermsForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('fieldX', 'fieldY', ...)

Pass them to your template in different variables and break up the formsets:

<form ...>
   <fieldset><legend>Personal Information</legend>
       {{ personal_info_form }}
   </fieldset>
   <fieldset><legend>Terms and Conditions</legend>
       {{ terms_form }}
   </fieldset>
</form>

In that sense each of your form classes is just a fragment of the actual HTML form.

It introduces a touch of complexity when you call save on the form. You'll probably want to pass commit=False and then merge the resultant objects. Or just avoid using ModelForm.save altogether and populate your model object by hand with 'cleaned_data'

把回忆走一遍 2024-07-21 00:29:54

Daniel Greenfeld 的 django-uni-form 通过 Layout 辅助类解决了这个问题。 我现在正在尝试,它对我来说看起来很干净。

统一助手可以使用布局对象。 布局可以由字段集、行、列、HTML 和字段组成

我最初选择 Django-uni-form 是因为它符合 第 508 条

Daniel Greenfelds django-uni-form solves this with a the Layout helper class. I'm trying it out right now and it looks pretty clean to me.

Uniform helpers can use layout objects. A layout can consist of fieldsets, rows, columns, HTML and fields.

I originally picked Django-uni-form because it complies with section 508.

暖风昔人 2024-07-21 00:29:54

您可以使用此包:https://pypi.org/project/django-forms-fieldset/

pip install django-forms-fieldset

将 forms_fieldset 添加到您的 INSTALLED_APPS 设置中,如下所示:

INSTALLED_APPS = [
    ...
    'forms_fieldset',
]

在表单中添加 fieldsets

from django.forms import ModelForm

from .models import Student

class StudentForm(ModelForm):
    fieldsets = [
        ("Student Information", {'fields': [
            ('first_name', 'last_name'),
            ('email', 'adress'),
        ]}),
        ("Parent Information", {'fields': [
            'mother_name',
            'father_name',
        ]}),
    ]
    class Meta:
        model = Student
        fields = '__all__'

视图中

def home(request):
    form = StudentForm()
    if request.method == 'POST':
        form = Form(request.POST, request.FILES)
        #save...
    context = {
        'form': form,
    }
    return render(request, 'home.html', context)

在您的模板

{% load forms_fieldset static %}
<link rel="stylesheet" type="text/css" href="{% static 'forms_fieldset/css/main.css' %}">

<form>
    {{ form|fieldset:'#42945c' }}
</form>

You can use this package: https://pypi.org/project/django-forms-fieldset/

pip install django-forms-fieldset

Add forms_fieldset to your INSTALLED_APPS setting like this:

INSTALLED_APPS = [
    ...
    'forms_fieldset',
]

Add fieldsets in your form

from django.forms import ModelForm

from .models import Student

class StudentForm(ModelForm):
    fieldsets = [
        ("Student Information", {'fields': [
            ('first_name', 'last_name'),
            ('email', 'adress'),
        ]}),
        ("Parent Information", {'fields': [
            'mother_name',
            'father_name',
        ]}),
    ]
    class Meta:
        model = Student
        fields = '__all__'

In your views

def home(request):
    form = StudentForm()
    if request.method == 'POST':
        form = Form(request.POST, request.FILES)
        #save...
    context = {
        'form': form,
    }
    return render(request, 'home.html', context)

in your template

{% load forms_fieldset static %}
<link rel="stylesheet" type="text/css" href="{% static 'forms_fieldset/css/main.css' %}">

<form>
    {{ form|fieldset:'#42945c' }}
</form>
ゃ懵逼小萝莉 2024-07-21 00:29:54

这是我为了理解自定义标签(带有链接)而开发的代码。 我应用它来创建一个字段集。

免责声明:我鼓励使用上述任何答案,这只是为了学习。

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>

This was the code that I developed in order to understand custom tags (with links). I applied it to create a fieldset.

Disclaimer: I encourage the use of any of the above answers, this was just for the sake of learning.

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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文