Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Crispy Form Split Field Layouts

We have a crispy form where we want to be able to render different fields in different parts of our forms HTML template, however we can't find a way of doing this in the Crispy Documentation. Below is some slightly made-up code to illustrate what we are trying to do:

forms.py

helper = FormHelper()
helper.layout_1 = Layout(
    Div(
        Field('field_1a'),
        Field('field_1b')
    )
)
helper.layout_2 = Layout(
    Div(
        Field('field_2a'),
        Field('field_2b')
    )
)

template.html

<body>
    {% crispy form layout_1 %}
    <!-- A big bunch of other html -->
    {% crispy form layout_2 %}
</body>

Does anyone know a clean way of achieving this?


The approaches we have looked at so far and had to rule out:

  • We could manually add the fields in our HTML instead of having crispy render them for us. However, this looks to be a no-go because we have a number of choice fields whose options are determined programmatically.
  • We could write a crispy layout which uses an crispy.forms.layout.HTML object to include the HTML which splits up the two different parts of our layout. However, there is a lot of HTML and it would become difficult to maintain if we embedded this directly into python.
  • We could write a Custom Layout Object to do this for us, however we predict this would be quite involved and want to consider this a last resort.
  • We could just not use crispy, and instead look for ways outside of crispy to achieve this, but then we would lose consistency with all the other forms in our application.
like image 200
robjohncox Avatar asked Jul 22 '13 10:07

robjohncox


2 Answers

Update: This does not work for forms.ModelForm

Try creating two helpers instead of two layouts then explicitly calling your separate helpers. Doing it this way you will have to manually write <form> tags to enclose both forms in your template but hopefully provides the solution you need.

forms.py

class Form(forms.Form):
    field_1a = forms.CharField()
    field_1b = forms.CharField()
    field_2a = forms.CharField()
    field_2b = forms.CharField()

    def __init__(self, *args, **kwargs):
        super(Form, self).__init__(*args, **kwargs)
        self.helper1 = FormHelper()
        self.helper1.form_tag = False
        self.helper1.layout = Layout(
            Div(
                Field('field_1a'),
                Field('field_1b')
            )
        )

        self.helper2 = FormHelper()
        self.helper2.form_tag = False
        self.helper2.disable_csrf = True
        self.helper2.layout = Layout(
            Div(
                Field('field_2a'),
                Field('field_2b')
            )
        )

Then in your template:

<body>
<form>
{% crispy form form.helper1 %}
<!-- A big bunch of other html -->
{% crispy form form.helper2 %}
</form>
</body>
like image 109
Scott Woodall Avatar answered Oct 18 '22 03:10

Scott Woodall


create a form.py

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Field,Layout, ButtonHolder, Submit
class layout1Form(forms.Form):    
    def __init__(self, *args, **kwargs):
        super(layout1Form, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.layout = Layout(
           Field('answer',css_class="field span8"),
           ButtonHolder(
              Submit('submit', 'Submit', css_class='btn-primary pull-right')
            )
          )
        self.helper.form_tag = False

class layout2Form(forms.Form):    
    def __init__(self, *args, **kwargs):
        super(layout1Form, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.layout = Layout(
           Field('answer',css_class="field span8"),
           ButtonHolder(
              Submit('submit', 'Submit', css_class='btn-primary pull-right')
            )
          )
        self.helper.form_tag = False

then in views.py

views.py

from ...forms import layout1Form,layout2Form
def layouttest(request):
    form = layout1Form(request.POST)
    form1=layout2Form(request.POST)
    return render(request,'test.html',{'frm1':form,'frm2':form1})

then in templates you can use in

test.html

<form id="signup" class="form-horizontal" method="post" action="">
{% crispy frm1 %}
   ""the big html""
{% crispy frm2 %}
<button type="submit" class="btn btn-success">Submit</button>   
</form>
like image 27
suhailvs Avatar answered Oct 18 '22 03:10

suhailvs