Django and fieldsets on ModelForm

前端 未结 5 1434
失恋的感觉
失恋的感觉 2020-12-04 10:34

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 somet

相关标签:
5条回答
  • 2020-12-04 10:40

    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

    0 讨论(0)
  • 2020-12-04 10:40

    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.

    0 讨论(0)
  • 2020-12-04 10:41

    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:

    • Form splitting/Fieldset templatetag
    • Sectioned Form
    • Forms splitted in fieldsets

    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 :)

    0 讨论(0)
  • 2020-12-04 10:56

    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'

    0 讨论(0)
  • 2020-12-04 11:04

    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>
    
    0 讨论(0)
提交回复
热议问题