Django: How to check if field widget is checkbox in the template? - python

I've created a custom template for rendering form fields:
<tr class="{{field.field.widget.attrs.class}}">
<th class="label">
<label for="{{field.auto_id}}">
{{field.label}}
{% if not field.field.required %}<span class="optional">(optional)</span>{% endif %}
</label>
</th>
<td class="field">
{{field}}
{% if field.errors %}<label class="error" for="{{field.auto_id}}">{{field.errors.0}}</label>{% endif %}
{% if field.help_text %}<small class="help-text">{{field.help_text}}</small>{% endif %}
</td>
</tr>
But I want to check if the widget is a checkbox, and if so, render it differently. How can I do that in the template?

Use a custom template filter!
In yourapp/templatetags/my_custom_tags.py:
from django import template
from django.forms import CheckboxInput
register = template.Library()
#register.filter(name='is_checkbox')
def is_checkbox(field):
return field.field.widget.__class__.__name__ == CheckboxInput().__class__.__name__
In your template:
{% load my_custom_tags %}
{% if field|is_checkbox %}
do something
{% endif %}
Side note on implementation: when I don't instantiate a CheckboxInput, the class name is MediaDefiningClass.
>>> form django.forms import CheckboxInput
KeyboardInterrupt
>>> CheckboxInput.__class__.__name__
'MediaDefiningClass'

{{ field.field.widget.input_type }} will get you this info for a lot of widgets, but not all. I'm not sure if it'll work for the default checkbox widget or not. Worth a shot.

It is kind of late to answer, but I implemented something similar to what is done in Django's admin.
First, I added a new attribute is_checkbox to the Field class:
# forms.py
from django import forms
from django.forms.fields import Field
setattr(Field, 'is_checkbox', lambda self: isinstance(self.widget, forms.CheckboxInput ))
Then, I can easily detect a CheckboxInput widget in the template. Here is an example to render checkboxes to the left and other widgets to the right:
{% if field.field.is_checkbox %}
{{ field }} {{ field.label_tag }}
{% else %}
{{ field.label }} {{ field }}
{% endif %}

Related

How can I show a specific django field in html?

So I want to do what the title says and I don't know how since I'm new at this.
<p>{{ form.description }}</p>
That's the way I show information from different models in a listing using
{% for form in forms %}
But I want to show the description of an specific object.
Thanks in advance.
<form method="post" novalidate>{% csrf_token %}
{{ form.non_field_errors }}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
<table border="1">
{% for field in form.visible_fields %}
<tr>
<th>{{ field.label_tag }}</th>
<td>
{{ field.errors }}
{{ field }}
{{ field.help_text }}
</td>
</tr>
{% endfor %}
Look this article: [link][1]https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html
Usually django templates will be filled with the data rendered from the django views as dictionary and these will be callable in templates using django template tags "{{tag_name}}"
Here you will be rendering all the forms as a list inside the dictionary so you can show each form by looping it.
{% for form in forms %}
{{form.description}}
{% endfor %}
Like this, you can show each form's data. Instead of this if you only want to show a specific form's data then the proper way is to render the view with the specific form's data and show data in template using the template tag {{form.description}}
Check the django documentation : https://docs.djangoproject.com/en/2.1/topics/templates/

Django Forms: styling forms (checkboxes) manually - Input to be outside of label

I need to render checkbox form fields in the following format in html template:
<input id="tag" type="checkbox" name="check" value="1">
<label for="tag">Tag 1</label>
Currently, in my template I tried:
{{ filter.form.tags.errors }}
{% for field in filter.form.tags %}
<input id="{{ field.id_for_label }}" type="checkbox" name="check">
<label for="{{ field.id_for_label }}">{{ field.value }}</label>
{% endfor %}
This will not render {{ field.value }} (I get empty instead of Tag 1) and also is non sticky.
I also tried:
{% for field in filter.form.tags %}
{{ field.label_tag }}
{{ field }}
{% endfor %}
Which gives me nested of <label><input></input></label>, but displays everything that I need.
Is it possible to render a form such that I get the format that I'm after? (It should also preserve checked e.g. make ticks sticky).
Edit:
class TaskFilter(django_filters.FilterSet):
"""Filter for books by author"""
tags = django_filters.ModelMultipleChoiceFilter(widget=forms.CheckboxSelectMultiple, queryset=Task.tags.most_common())
title = django_filters.CharFilter(field_name='title', lookup_expr='icontains')
class Meta:
model = Task
fields = ['tags', 'title']
views.py
def task_list_filter(request):
if request.method == 'GET':
form = AdditionalForm(request.GET)
# process the form
results = Task.objects.all().order_by('-created')
f = TaskFilter(request.GET, queryset=results)
# Output final query set
results = f.qs[0:100] # only get first 100 objects
# Create pagination
# Get the view
return render(request, 'base/task_list_filter.html', {'filter': f,
'task_list': results,
'form': form })
To make sure the checkbox is in the correct state you can use the example you yourself provided with a few changes:
{% for field in filter.form.tags %}
<input type="checkbox" id="{{ field.id_for_label }}"
name="{{ field.html_name }}"
{% if field.value %}checked{% endif %}>
<label for="{{ field.id_for_label }}">{{ field.value }}</label>
{% endfor %}
And remember that you can use the {{ field.label_tag }} to generate the entire label HTML tag.
In HTML
{% for field in filter.form.tags %}
{{ field.tag }} <!-- Generates the checkbox for the field -->
{{ field.choice_label }} <!-- Generates the named label of the field -->
{% endfor %}
I learned that from this guy who has lots of helpful information specific to using Django.

WTForms Can I add a placeholder attribute when I init a field?

I want to add a placeholder attribute on to the field in WTForms. How can I do it?
abc = TextField('abc', validators=[Required(), Length(min=3, max=30)], placeholder="test")
The above code is not valid
How can I add a placeholder attribute with value?
Updated for WTForms 2.1
You can now as of WTForms 2.1 (December 2015) set rendering keywords by using the render_kw= parameter to the field constructor.
So the field would look like:
abc = StringField('abc', [InputRequired()], render_kw={"placeholder": "test"})
Note while this is possible; it does start to bridge the line between code and presentation; so use it wisely!
(Old answer, still true for versions older than WTForms 2.1)
placeholder is not supported in the Python constructor in WTforms 2.0.x and below.
However, you can do this easily in your template:
{{ form.abc(placeholder="test") }}
Correct answer is as follows:
abc = TextField('abc', validators=[Required(), Length(min=3, max=30)], description="test")
As one can read in documenatation:
description – A description for the field, typically used for help text.
Then in your template:
{% import 'forms.html' as forms %}
{% for field in form %}
{{ forms.render_field(field) }}
{% endfor %}
Where render_field is a macro that is defined in forms.html:
{% macro render_field(field) -%}
{% if field.type == 'CSRFTokenField' %}
{{ field }}
{% if field.errors %}
<div class="warning">You have submitted an invalid CSRF token</div>
{% endif %}
{% elif field.type == 'HiddenField' %}
{{ field }}
{# any other special case you may need #}
{% else %}
<div class="form-group">
<label for="{{ field.label.field_id }}" class="col-sm-2 control-label">{{ field.label.text }}</label>
<div class="col-sm-10">
{{ field(placeholder=field.description) }}
{% if field.errors %}
<div class="alert alert-danger" role="alert">
{% for err in field.errors %}
<p>{{ err|e }}</p>
{% endfor %}
</div>
{% endif %}
</div>
</div>
{% endif %}
{%- endmacro %}
{{ form.username(class="input", placeholder="Please enter your username") }}
My solution is use a custom widget:
from flask.ext.wtf import Form
from wtforms import StringField, validators
from wtforms.widgets import Input
class CustomInput(Input):
input_type = None
def __init__(self, input_type=None, **kwargs):
self.params = kwargs
super(CustomInput, self).__init__(input_type=input_type)
def __call__(self, field, **kwargs):
for param, value in self.params.iteritems():
kwargs.setdefault(param, value)
return super(CustomInput, self).__call__(field, **kwargs)
class CustomTextInput(CustomInput):
input_type = 'text'
class EditProfileForm(Form):
first_name = StringField('First name',
validators=[validators.DataRequired()],
widget=CustomTextInput(placeholder='Enter first name'))
Maybe it's not ellegant, but it allows to use Flask-Bootstrap and define your forms in the forms code, not in the template

Is there anything like Generic templates in django like Generic views

Generic view have saved lot of code for me but i still have to write templates of every model. I have same code in all template i.e
<form action="/{{type}}/{{ action }}/" method="post" enctype="multipart/form-data" >
{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Submit" /></p>
</form>
i.e basically i want to have all fields from the model to add or edit.
is there any work around to have generic template automatrically
If you have template code that is identical, you can use the include tag:
{% include "foo/bar.html" %}
And the included code can be modified with variables:
{% include "name_snippet.html" with person="Jane" %}
Even if the code is different for each template (I think your example is talking about forms having different fields, not sure), you can still use includes - just make two blocks:
{% include "startform.html with some_action="post" %}
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
{{ field.field2_tag }}: {{ field2 }}
{% include "endform.html %}
There is also template inheritance, where you can define a basic template, and have all your other templates inherit from it. Inheritance is block-based, you can override blocks in the parent template with new code in the child template. It works very well.
In django, templates can be generic itself!!
You can use a diferent form for each model inside the same template using {{ form.attribute }}
Here is the django oficial doc
Look at the ModelForm helper app. It will make a form from any model which can then be used in a simple form template.

Django admin display multiple fields on the same line

I have created a model, it will automatically display all the fields from the model and display it on the admin page.
Now, I have a problem, I would like to have two fields on the same line, to do this I have to specify the fieldsets at ModelAdmin:
fieldsets = (
(None, {
'fields': (('firstname', 'lastname'),)
}),
)
Do I have to specify all the fields? Because there are many fields in the database I need to specify.
Wrap those fields on their own tuple.
class TestAdmin(admin.ModelAdmin):
fields = (
'field1',
('field2', 'field3'),
'field4'
)
In the above example, fields field2 and field3 are shown on one line.
I'm afraid there's not an easy way to do it.
One option is to override the change_form.html template for that ModelAdmin and style the form as you like.
Another alternative is to do custom ModelForm and define a field with a widget that renders two input fields, in the form's .save() method, set the widget resulting value (a tuple) to both fields.
There is an article may be useful
http://amk1.wordpress.com/2010/09/23/a-2-column-django-admin-form/
Article is quote below:
Django is great. The bundled admin interface makes it better. But as the number of items on the form gets bigger, the amount of wasted space increases because the layout is single column. Coupled with left alignment on wide-screen monitors, my users usually end their day with a condition we call “eyeballs misalignment”.
So I improvised and changed the form (and StackedInline) to a 2-up layout. No more “eyeballs misalignment”.
The corresponding template for Django 1.2.1 (/contrib/admin/templates/admin/includes/fieldset.html) looks like this, modified lines highlighted:
<fieldset class="module aligned {{ fieldset.classes }}">
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
{% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
<table border=0 width=100%>
{% for line in fieldset %}
{% cycle '<tr>' '' %}
<td width=50%>
<div style="border-bottom:0" class="form-row{% if line.errors %} errors{% endif %}{% for field in line %} {{ field.field.name }}{% endfor %}">
{{ line.errors }}
{% for field in line %}
<div{% if not line.fields|length_is:"1" %} class="field-box"{% endif %}>
{% if field.is_checkbox %}
{{ field.field }}{{ field.label_tag }}
{% else %}
{{ field.label_tag }}
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{{ field.field }}
{% endif %}
{% endif %}
{% if field.field.field.help_text %}
<p class="help">{{ field.field.field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
</div>
</td>
{% cycle '' '</tr>' %}
{% endfor %}
</table>
</fieldset>
this has worked for me
fieldsets=(
("My Group",{"fields": (tuple(['field1','field1']),),}),
)
It's stupid, but yes, if you're going to use the fieldsets tuple-within-a-tuple method, you have to then specify all the fields that should show on your form.
Agreed, that its annoying, but its tuple of tuples from list of fields.
you can use list comprehension and change list to tuple.
Here is an example for skipping some fields, that you want to give some special attention WHILE including rest normal way.
skipped=[]
alist = [field.name for field in <model_name>._meta.fields if field.name not in skipped]
fieldsets = tuple(alist)
*** play with skipped ***
with small tweaking this should work.

Categories

Resources