django-formset
django-formset copied to clipboard
Render form will always render default template
Issue
I found that using the templatetag render_form will ignore the form renderer I declared in forms.py when I implement my project as follows:
from formset.renderers.bootstrap import FormRenderer as BootstrapFormRenderer
class Form(ModelForm):
default_renderer = BootstrapFormRenderer(
field_css_classes='row mb-3',
label_css_classes='col-sm-3',
control_css_classes='col-sm-9',
)
class Meta:
model = ...
fields = "__all__"
and template:
<django-formset endpoint="{{ request.path }}" csrf-token="{{ csrf_token }}">
{% render_form form %}
<div class="offset-sm-3">
<button type="button" click="submit -> proceed" class="btn btn-primary">Submit</button>
<button type="button" click="reset" class="ms-2 btn btn-warning">Reset to initial</button>
</div>
</django-formset>
Clarification
I'm not sure if this is correct since I'm still checking this out:
https://github.com/jrief/django-formset/blob/e12c947a519ce84510b15df07030ac2c77df2a39/formset/templatetags/formsetify.py#L49C1-L52C66
def render_form(context, form, *args, **kwargs):
get_token(context['request']) # ensures that the CSRF-Cookie is set
form = _formsetify(form, *args, **kwargs)
# shouldnt this:
return form.render(template_name='formset/default/form.html')
# be this:
return form.render()
It's causing rendering issues on my project since my ModelForm.default_renderer is bootstrap-based renderer,
while {% render_form form %} forces to use formset/default/form.html instead of formset/bootstrap/form.html
I would have to step through with the debugger, but usually you would use the Bootstrap Renderer class to render your forms. And here https://github.com/jrief/django-formset/blob/e12c947a519ce84510b15df07030ac2c77df2a39/formset/renderers/bootstrap.py#L17C39-L17C66 the default template is mapped to one specific to Bootstrap.
I agree to the reference. It is what I use, but when I check the rendered html, each field group follows
formset/default/field_group.html instead of formset/bootstrap/field.group.html
... which in turn, fails to create the inline formatting of labels and inputs as referenced here
This is due to the implementation of formset/default/field_group.html having no separate div classes for label and input, which formset/bootstrap/field_group.html wraps widget field inside a div element
So I'm not sure if the templatetags.formsetify.render_form should be adjusted, or, default/field_group.html needs a div class similar to bootstrap/field_group.html
Can you please create a small example. Take the examples in testapp as blueprint.
Investigatory diff:
- reference diff: https://github.com/jrief/django-formset/commit/f1391294e459b45d6a98b37ca168dee192cee24b
- access http://localhost:8000/bootstrap/custom-bootstrap-renderer
- expectation: label and input should be inline
- findings: If you check dev-tools, you will see that the html being renderered is
default/field_group.html
<!-- snippet -->
<div role="group" class="dj-required row mb-3">
<label for="id_name" class="col-sm-3">Team name:</label><input type="text" name="name" maxlength="50" required="" form="id_customrendererteamform" id="id_name" class="form-control">
<div role="alert" class="dj-field-errors">
<meta name="error-messages" value_missing="This field is required." too_long="Ensure this value has at most 50 characters." bad_input="Null characters are not allowed.">
<ul class="dj-errorlist">
<li class="dj-placeholder"></li>
</ul>
</div>
<div class="dj-help-text">The name of the team</div>
</div>
Overridden diff:
- reference diff: https://github.com/jrief/django-formset/commit/84b9e1cf07a72c959a10fbae9edbb052c5fe971c
- access http://localhost:8000/bootstrap/correct-custom-bootstrap-renderer
- findings: If you check dev-tools, you will see that the html being renderered is
bootstrap/field_group.html
<!-- snippet -->
<div role="group" class="row mb-3 dj-required">
<label for="id_name" class="col-sm-3">
Team name:</label>
<div class="col-sm-9">
<input type="text" name="name" maxlength="50" required="" form="id_customrendererteamform" id="id_name" class="form-control">
<div role="alert" class="dj-field-errors">
<meta name="error-messages" value_missing="This field is required." too_long="Ensure this value has at most 50 characters." bad_input="Null characters are not allowed.">
<ul class="dj-errorlist">
<li class="dj-placeholder"></li>
</ul>
</div>
<div class="form-text text-muted">The name of the team</div>
</div>
</div>
Some Notes:
- I had to externally import bootstrap cdn since I had issues loading static files when trying to run webapp (It's kind of irrelevant to the investigation but provides us with needed visual cues)
- Implementation assumes having a CreateView inheriting native django CreateView that:
- takes in form_class with override of
default_renderer=BootstrapFormRenderer - overrides template that uses
{% render_form form %}
- takes in form_class with override of
- I also tried using
{{form}}instead of{% render_form form %}. Doing so will partially render the form correctly except for field_css_clases but will raise 422 on submit, consequently, will to fail to create an instance. I'm not sure if it's an implementation issue or a limitation (which is why render_form is needed) - I find that https://github.com/jrief/django-formset/commit/84b9e1cf07a72c959a10fbae9edbb052c5fe971c works for my usecase but I'm not sure if it's all encompassing solution or would affect implementation
Hopefully implementation is readable enough!
On branch https://github.com/jrief/django-formset/tree/releases/1.5 I have solved this. I used your sample code and applied them to an existing model in testapp.
Please try the examples at http://localhost:8000/bootstrap/person-bootstrap-params and http://localhost:8000/bootstrap/person-bootstrap-renderer
The first uses
{% render_form form "boostrap" field_classes="row mb-3" label_classes="col-sm-3" control_classes="col-sm-9" %}
while the second uses a form with
class PersonFormBootstrapRenderer(FormMixin, PersonForm):
default_renderer = BootstrapFormRenderer(
field_css_classes='row mb-3',
label_css_classes='col-sm-3',
control_css_classes='col-sm-9',
)
I haven't tested this with Bootstrap loaded from a CDN though.
Thanks for reporting.