Django - wrap each form element in a <div> - django

The Django forms API has methods Form.as_p(), Form.as_table() and Form.as_ul(), which wrap form elements in <p>, <tr> and <li> tags respectively.
Is there any way to wrap form elements in a <div>, like in the canonical Bootstrap forms example?

Why not render form fields manually?
With this ability you have absolute freedom of how you can manipulate the "look" of a form. You can define CSS classes, ids etc.

Related

How can one create a custom "as_table()" method for forms?

I have a relatively complicated form that's used in multiple places on my website (in fact, it's a form from which many other form classes inherit). In the templates, the inherited part of this form is always formatted identically—but that formatting is somehwat involved; each field is rendered and positioned manually in the template.
This means that every template which displays this form has a lot of identical HTML markup that renders the form appropriately.
I would like to create a custom output that can be called, similar to the as_table() methods. I'm aware that one can override the normal_row, error_row, etc. attributes—but the formatting of this form goes beyond that (for example, three of the form's five fields should be printed side-by-side, with a combined title). All of the tutorials/answered-questions I've seen either refer to overriding the above-mentioned attributes, or give instructions on how to manually render forms.
Originally, I was thinking something like this:
Class StrangeForm(form.Forms):
....
def as_table_custom():
html_string = "\
<tr><td>Title 1:</td><td>self.fields['field1']</td><tr>\
<tr><td>Title 2:</td><td>self.fields['field2']</td><tr>\
<tr><td>Titles 3, 4, 5:</td><td>self.fields['field3']\
</td><td>self.fields['field4']</td><td>self.fields['field5']</td></tr>\
"
return html_string
But, after reading through the _html_output() and as_table() methods of Django's forms.py file, it doesn't look like it'll be that easy. If I write this from scratch, have to somehow account for errors, help text, etc. I think.
Is there an easy way to override something such that the form's HTML output can be defined like above? Or do I have to re-write things from scratch. If the latter, how can I account for all of the things I need to account for?
I wouldn't take this approach. You're better off creating the form in an HTML template that you include in the various templates where you have a form you want to display that way.
So create a my_strange_form.html template where you assume a 'form' object is passed in the context with the right number of fields. In that template just create the HTML, using things like {{ field.label_tag }} and {{ field }}. You can loop through the fields with a {% for field in form %} and check the counter of your loop with {{ forloop.counter }}. I foresee a lot of {% if forloop.counter... %} statements to generate the combined row, and it will look ugly, but you'll only have to look at it once :-)
Then in your main templates {% include 'my_strange_form.html' with form=form %}.

Hiding ModelMultipleChoiceField on template for custom input

I want the user to select a number of elements belonging to a certain model. I don't want to use the default 'ctrl+click' input of django forms, but create a table of checkboxes myself.
For that reason I hide the ModelMultipleChoiceField by defining the widget:
field = forms.ModelMultipleChoiceField(..., widget=forms.MultipleHiddenInput())
Then I add the form element into the template as follows:
<form method="POST" class="locklist-form" id="locklist-form">{% csrf_token %}
{{ form.field }}
</form>
At this step, I expect the select-option elements to be added to HTML page (as hidden), so that I can reach to element options and modify them with javascript. However, it doesn't add anything to the HTML page.
I use this approach with other type of form fieds. For a TextField HTML page have a hidden element as shown:
Why doesn't it work with ModelMultipleChoiceField? How can I modify the choices of this field with Javascript?
Edit:
MultipleHiddenInput renders only if with initial data is a similar question. But applying it doesn't lead to the expected solution. In this question, it is expected to render the following as hidden:
But following the MultipleHiddenInput renders only if with initial data, when I modify the form constructor as:
form = MyForm(initial={'field':MyModel.objects.all()})
Rendered element is as follows:
It maybe useful, but not exactly the expected one. I need to mark a few options as selected, among a list of objects.
I have done it using Javascript, instead of depending on Django's capabilities. I add the form with ModelMultipleChoiceField directly to the template (not hidden). Then I run a Javascript script, when the page is loaded:
var field = document.getElementById('id_field');
selecter.setAttribute('class', 'hidden');
CSS definition of hidden class is as follows:
.hidden{
display: none;
}
This gets me to the desired situation. ModelMultipleChoiceField is rendered hidden as follows:
At this point, I can modify certain items through Javascript:
document.getElementById('id_field').options[index].selected = boolValue;

TableBlock how to specify table CSS classes

I am struggling to add CSS classes to Wagtail StreamField & TableBlock (http://docs.wagtail.io/en/v1.8.1/reference/contrib/table_block.html).
Is the way to go to define a filter and use something like:
{{ child|className:"table table-bordered" }}
where className is my custom filter?
No, this isn't currently possible with the standard rendering of a TableBlock - the template used internally to render the block has hard-coded <table> / <tr> / <td> tags with no class attributes. However, you could specify a custom template in your TableBlock declaration, which would give you full control over the HTML:
StreamField([
# ...
('table', TableBlock(template='/path/to/custom/template.html')),
# ...
])
I think it's a good idea. Last time I needed to do something similar I found this blogpost which gives you a practically copy-and-paste solution to your problem. Django templatetags might have changed since then, but not by much.
EDIT: From the comments, this seems to be more modular.

Setting html-attributes to HTML forms using serializer in Django

I want to make page with form that contains any kinds of inputs. I'm using Django and rest framework. I've succeded in representing HTML form using rest framework {% render_form %} tag and serializer with some fields. But i'm just able to set few attributes, for instance, placeholder and input_type. And it works well. The next thing I want is setting some #id, .class and any attributes to input tags(or select) on a server side because I need to handle these HTML forms using knockoutjs or JQuery but I can't do it without data-bindings or #IDs. I couldn't find any information about it. I guess it is possible to set any attributes to inputs on client-side finding them by label name but it seems a bad way. Or maybe I could get list of fields and just represent it in html template? Are there some pieces of advice?

Django forms: How to add class to field_content?

When I render a form, it generates something like this for each Field:
<div class="field_content">
<label>...</label>
<div class="field">...</class>
</div>
I would like to be able to uniquely identify each Field in my stylesheet. Is there a way to add another class to the outer div (in addition to field_content), or an outer div (parent to field_content)?
If it's enough to set the class of the field you can specify it as an attribute of your widget:
name = forms.CharField(widget=forms.TextInput(attrs={'class':'special'}))
If you need more control it's probably best to render your form manually or if you don't mind relying on an external app there are even more flexible solutions:
In django-floppyforms you could use form layouts and in django-crispy-forms you could use layout objects and to achieve what you want.