Django and crispy form, how to add id and name in the crispy Layout

Viewed 2860

I'm trying to use Crispy Forms in my template, but I can't get name, id and class to render properly in the layout. In other words I have the following templates:

 <div class="modal-body">
        <label for="conto">Conto</label>
        <input class="form-control" id="form-conto" name="formConto"/>
 </div>

So I want to delete the input row and add the crispy field, such that id="form-conto" name="formConto" on the input field.

I know that I have to add the layout in my Model.forms but I do not understand how get it.

This is my form:

class MaterialeForm(forms.ModelForm):

    class Meta:
        model = Materiale
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()

And here my models:

class Materiale(models.Model):
    conto = models.ForeignKey(Conto, on_delete=models.CASCADE, null=True)
1 Answers

At the top of your template, load the crispy tags:

{% load crispy_forms_tags %}

Then, tell Crispy to render your form by using the Crispy tag:

<div class="modal-body">
  {% crispy materialeform materialeform.helper %}
</div>

In your forms.py, you'll need to add a Layout:

from crispy_forms import FormHelper, Layout

... 

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.layout = Layout(
            Field('conta', id="form-conto", css_class="form-control", title="Conto")
        )

See the docs on Layout: https://django-crispy-forms.readthedocs.io/en/latest/layouts.html

Then, when the GET request is made for the form, it will be rendered (more or less) as you desire. You may have to tweak some things. Follow the layout docs above to get there.

But none of this will work unless you actually pass the form in your template. Perhaps you are already doing this, e.g., with a generic FormView, but in case not, here's what you'll need in the view:

from .forms import MaterialeForm
from django.template import RequestContext

def materialeview(request, template_name):
    materialeform = MaterialeForm()

    # Form handling logic
    [...]

    return render_to_response(template_name, {'materialeform': materialeform}, context_instance=RequestContext(request))

On RequestContext, see https://docs.djangoproject.com/en/3.0/ref/templates/api/#using-requestcontext.

For more on Crispy Forms, see https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html.

Finally, since Crispy Forms does a lot in the background, you could consider removing confusion by telling it to fail loudly. Put this in your settings.py file:

CRISPY_FAIL_SILENTLY = not DEBUG

As an aside, let me say that Crispy Forms will likely cause much confusion if you do not yet understand Django Forms well. I'd say start with Django's built-in Forms first and then get crispy later when you want to do more advanced stuff. The docs here should help: https://docs.djangoproject.com/en/3.0/topics/forms/.

Related