class BaseForm(forms.Form):
def as_custom_table(self):
"Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
return self._html_output(
normal_row = u'<tr%(html_class_attr)s><td class="label_col">%(label)s</td><td class="field_col">%(field)s%(help_text)s</td></tr>',
error_row = u'<tr><td colspan="2" class="error">%s</td></tr>',
row_ender = u'</td></tr>',
help_text_html = u'<br />%s',
errors_on_separate_row = True)
I'm trying to see if I can get django to do the heavy lifting and render a form in the way I want it to render.
The problem here is, there might be one or two fields that need to render slightly differently. Such as a "please confirm you agree to our terms and conditions" check box, which would need to span two columns.
Also some other things, such as error placement, might need changing.
I could override the _html_output method to change error placement, but what about getting an individual field to use a different render method?
I think ultimately I need to revert to manually building the form html in the template, but I'm just wondering how much of it Django could do for me with some minor modifications.
The suggested method will be to use a template like this:
<form action="/contact/" method="post">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Send message" /></p>
</form>
You can conditionally override specific fields using {{ if field.my_property }}.
Related
Summary: I am upgrading a django-project from bootstrap3 to bootstrap4, so I am using django-bootstrap4 now.
The is-valid tags on form elements are, after upgrade to bootstrap4, rendering a big green tick and making the form fields wider.
How do I stop is-valid tags being added? This is even before the form has been submitted.
There is no validation logic.
more:
I have a filter form generated on some of my pages
{% if filter %}
<form action="" method="get" class="form form-inline">
{% bootstrap_form filter.form layout='inline' %}
{% bootstrap_button 'filter' %}
</form>
{% endif %}
The form fields are generating markup like:
<div class="form-group is-valid">
<label class="sr-only" for="id_order_number__icontains">Order number contains</label>
<input type="text" name="order_number__icontains" class="form-control is-valid" placeholder="Order number contains" title="order_number__icontains" id="id_order_number__icontains">
</div>
The <input> element has been assigned class is-valid. This happens to all elements.
Previously this happened too, but there was no visual effect. Bootstrap4 is making the field wider and displaying a big green tick. I don't think the fields should be marked is-invalid before submission, this doesn't make much sense to me. I don't have validation scripts, and if I disable javascript on the page, I get the same result anyway.
You appear to be using a form to filter a queryset. Naturally such forms would be bound irrespective of whether the form is submitted since they are always passed the GET parameters, and hence would be valid even when rendered first when not submitted.
If you don't want the is_valid class to be added you can pass the class that should be rendered instead as the keyword argument bound_css_class to the bootstrap_form template tag:
{% bootstrap_form filter.form layout='inline' bound_css_class='' %}
Displaying forms in a template is rather easy in Django:
<form action="" method="post">{% csrf_token %}
{{ form }}
<input type="submit" value="Update" />
</form>
It is basically just one word - display the {{ form }}. It is so simple that you can use the same template for different forms.
You can limit the fields to be shown on the form using the fields = [] list if you are using CBV's such as CreateView or UpdateView.
Drawing parallel to this, one expects to have a similar workflow for showing the models as well (as opposed to editing) such as in DetailView. But, there is no such thing.. You have to write a custom template for every DetailView that you use. Such as:
<h3>User: {{ user }}</h3>
<label>First Name</label>: {{ user.first_name }} <br />
<label>Last Name</label>: {{ user.last_name }} <br />
<label>Username</label>: {{ user.username }} <br />
<label>School</label>: {{ user.person.school.name }} <br />
This is very similar to what the {{ form }} would generate, except for the field values printed here, as opposed toinputs being printed there.
So, I wonder, why isn't there a reusable generic template for DetailView's? Is there a technical limitation for this, or is it just not as reusable as I imagine?
I have created and have been using gladly for about a year now my own generic templates. So, I wanted to share, here it is:
Creating a view is as simple as this:
class PersonDetail(DetailViewParent):
model=Person
DetailViewParent used above (override fields and exclude as needed; default is to include all):
class DetailViewParent(DetailView):
fields=[]
exclude=[]
template_name='common/modal_detail.html'
def get_context_data(self, **kwargs):
context=super(DetailViewParent, self).get_context_data(**kwargs)
context['exclude']=self.exclude
context['fields']=self.fields
return context
Relevant part of the template:
{% fields %}
{% for name, label, value, is_link in fields %}
<tr>
<td><strong>{{ label|capfirst }}</strong></td>
<td>
{% if value.get_absolute_url and request.is_ajax %}
<a class="modal-loader" href="{{ value.get_absolute_url }}">{{ value }}</a>
{% elif value.get_absolute_url %}
{{ value }}
{% else %}
{% if is_link and request.is_ajax %}
<a class="modal-loader" href="{{ value }}">{{ value }}</a>
{% elif is_link %}
{{ value }}
{% else %}
{{ value }}
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
And the template tags:
#register.tag(name="fields")
def generate_fields(parser, token):
"""
{% fields %} - loads field name, label, value, is_link to the context
"""
args=token.contents.split()
object_name='object'
if len(args) == 2:
object_name=args[1]
return FieldsNode(object_name)
class FieldsNode(template.Node):
"""
called by generate_fields above
"""
def __init__(self, object_name):
self.object_name=object_name
def render(self, context):
# Get the data necessary for rendering the thing, and add it to the context.
try:
obj=template.Variable(self.object_name).resolve(context)
except template.VariableDoesNotExist:
return ''
include_fields=context.get("fields", None)
exclude_fields=context.get("exclude", None)
fields=[]
for field in obj._meta.fields:
name=field.name
if exclude_fields and name in exclude_fields:
continue
if include_fields and name not in include_fields:
continue
label=field.verbose_name
value=getattr(obj, field.name)
is_link=(type(field).__name__ in ('URLField',))
if isinstance(value, bool):
value=get_bool_check_mark(value)
elif value is None:
value=''
fields.append((
name, label, value, is_link,
))
# If include_fields was defined, then sort by the order.
if include_fields:
fields=sorted(fields, key=lambda field_: include_fields.index(field_[0]))
context['fields']=fields
return ''
The template might be customized to your needs and liking. But I would like to note two things:
1) get_absolute_url: if this (standard django) model method is defined, the field value is shown as url.
2) modal-loader class: this triggers js on the client side to show the detail view in a bootstrap 3 modal. Furthermore, if clicked on a link as mentioned in 1) that is loaded onto the same modal, thus making it easier to browse detail views. It has also a "back" button to go back to the previous model's view. I am not including that here because it is a lot of code, and beyond the scope of this question.
I think it is not as reusable as you imagine.
It might conceivably be possible to define "standard" ways to render simple model properties like CharField - this quickly becomes impossible when you get into more complex relational fields like ManyToManyField, ForeignKey, OneToOneField. You would end up overriding any default representation very quickly for anything but the simplest of models.
Secondly Django is not - and should not be - opinionated about what your models are for, and therefore it makes sense that it doesn't try to assume how you want to render them.
This is different from forms where the structure of individual form fields is defined in Django and in HTML, and there is a strong correlation between the two.
I have generated a simple contact form with four fields using Wagtail Form Builder. The challenge I'm having, is that I'm unable to reference the form fields with css classes individually, since I'm not sure where I should get the field id and label name from.
Here is the code that renders the form:
<h1>{{ page.title }}</h1>
{{ page.intro|richtext }}
<form action="{% pageurl page %}" method="POST" class="sky-form contact-style">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
If referencing the fields individually is not possible, what will be the other method(s) to achieve the same result?
Wagtail formbuilder creates a dynamic form - the id (name) of each field is created by the following code: str(slugify(text_type(unidecode(self.label))))
(from https://github.com/torchbox/wagtail/blob/master/wagtail/wagtailforms/models.py#L90)
So the field label is converted to ascii characters and then to a slug. For example, if you have a field name First Name it will be converted to 'first-name'.
An easy way to find out what is the actual id of the form fields that wagtail formbuilder creates is to actually output the fields in a template by enumerating them:
{% for field in form %}
{{ field }}
{% endfor %}
and then inspect the produced html code to see their actual ids (you'll see <input class="textinput textInput" id="id_first-name" maxlength="255" name="first-name" type="text"> so you'll know that the id of the field is first-name)
{% for fields in form %}
{{ field.label }}
{{ field }}
{% endfor %}
The {{ field }} will render something similar to:
<input type="text" id="something_id" .../>
Is there a way I can render a field without having to let it wrap it in a tag? So for instance, I render a field and I get (without the input tag):
type='text' id='_something_id'
In this case, I can go ahead to manually add custom classes as and when and where I want like:
<input {{ field }} class='class class-again' required autocomplete='off' />
Is there a way I can do that in Django, render a field without it wrapped in the element?
Obviously, such a hard way of formatting can be tiring if working on tons of fields making such an approach impractical. In my case, I'm just wanting to tailor some css to just two fields, and having to go through Django Forms, or template tags etc, I find the process lengthy
You can do this if you know the input type:
{% for field in form %}
{{ field.label_tag }}
<input type="text" id="{{ field.id_for_label }}" name="{{ field.html_name }}" value="{{ field.value }}"/>
{% endfor %}
If you have different input types you could still go through the fields manually instead of iterating over them (using their name, eg. form.username).
However in most cases it is better to do those things on the backend using the widget API like this:
name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
It is possible. You could write your own HTML code, you know that Django assigns id and name attributes with a format, like: id='something_id'. The name attribute is the important one, you should make sure it is the same that Django would assigns.
Another option is this:
# I will assume you have a field named something
something = forms.CharField(widget=forms.TextInput(attrs={'class':'class class-again''}))
This should do what you need. I hope this helps.
After reading over the Docs, and working with Django forms for quite a while, it would seem pretty standard to me that {{ form.as_p }} in the template would render a Django form. However, my situation is a bit different.
I have 2 checkboxes in my form:
class FORM(forms.Form):
field_a = forms.BooleanField(initial=False, label =('FIELD-A'))
field_b= forms.BooleanField(initial=True, label=('FIELD-B'))
I pass the form object as most would from the view:
context = {
'FORM':FORM(),
}
return render_to_string(template, context)
I am trying to use basic 'if' logic to see if I should display one, or both of the fields. I know most would say 'Just name them two separate forms', but I would prefer to keep them as one form for organization purposes.
THE PROBLEM
{% if BoolValue' %}
<form action='' method='post'>
{{ FORM.field_a }}
</form>
{% endif %}
This returns only the field, and not the field label (so just a checkbox). Going off of the Docs and other StackOverflow Questions, this should display the entire form, including the label, yet it doesn't.
These methods still work, however:
METHOD 1
{% for field in FORM%}
<div class="form">
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
This will display both forms, with their respective labels, and field inputs (checkboxes)
METHOD 2
{{ FORM.as_p }}
The traditional way of rendering the entire form will display both fields and labels, it is virtually identical to Method 1 in style and formatting.
EDIT
METHOD 3
{{ FORM.field_a.label_tag }} {{ Form.field_a }}
This will display the label and the form field. A possible work around, but I am looking for why {{ Form.field_a }} does not work on its own
So...
Why can I not render that individual form with its respective label? I am not looking for a work around so to speak, as I would like both fields to be under that one form. Any ideas?
Have you tried {{ FORM.field_a }} {{FORM.field_a.label_tag}}?