Custom HTML layout for forms in Django - django

I am new to Django and I'm trying to get a grip on it.
I worked my way through the documentation of forms.
And the Django way is doing basically:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
To render the according template. Fine.
I can mayually render my fields:
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
And I can customize the rendered output of a field with widgets.
class CommentForm(forms.Form):
name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
url = forms.URLField()
comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))
So far I am using some "standard rendering mechanism" which allows me to customize things a little bit.
Question: Is there any way to design the layout of a form in a more html-like way?
Say instead of {{ form.subject }} - rendering a default template enriched with widget information from somewhere else in the codebase - having something like <input type="text" minlength="10" class="wiggle" value="{{form.subject.value}}>.
Which for me would be a bit more straightforward.

Related

Django: Accessing queryset in ModelMultipleChoiceField from template

I'm creating a panel where a user can assign an assignment to other users. I'm attempting to build this with the ModelMultipleChoiceField and a form called AssignedUsersForm
forms.py
class AssignedUsersForm(ModelForm):
class Meta:
model = Assignment
fields = ['users']
custom_users = CustomUser.objects.all()
users = forms.ModelMultipleChoiceField(queryset=custom_users, widget=forms.CheckboxSelectMultiple())
template
<form method="post" id="assigned_users_form">
{% csrf_token %}
{{ assigned_users_form.errors }}
{{ assigned_users_form.non_field_errors }}
<div class="fieldWrapper">
{{ assigned_users_form.content.errors }}
{% for user in assigned_users_form.users %}
<div class="myradio">
{{ user }}
</div>
{% endfor %}
<br>
<div style="text-align:center;">
<input class="input-btn" type="submit" value="Save" name='submit_assigned_users_form'>
</div>
</form>
I've successfully rendered each of the options for CheckboxSelectMultiple individually in my HTML.
Unfortunately, each iteration of 'user' renders CustomUser object (#) - the default name for the object.
From what I understand, the Checkbox widget does not pass the original queryset to the template. Thus, I'm unable to access the model attributes of each user and render information such as name, profile picture, etc.
Is there a method of accessing the actual object that's represented in the checklist, instead of the _ str _ value?
I've considered running a parallel iteration of queryset in the template, but I'm not sure if that's possible in Django.
I've also considered creating custom template tags to access each object based on the id in str, but that seems like overkill?
Is there a more intuitive method that I'm missing here?
I found a work around by creating a template_filter that takes the checkbox value and returns the corresponding object to the template.
template_tags.py
#register.filter(name='get_user')
def get_user(user_id):
user = CustomUser.objects.get(pk=user_id.value)
return user
template
<form method="post" id="assigned_users_form">
{% csrf_token %}
{{ assigned_users_form.errors }}
{{ assigned_users_form.non_field_errors }}
<div class="fieldWrapper">
{{ assigned_users_form.content.errors }}
{% for user in assigned_users_form.users %}
<div class="myradio">
{% with customuser=user.data.value|get_user %}
{{user.tag}} {{customuser.first_name }}
{% endwith %}
</div>
{% endfor %}
<br>
<div style="text-align:center;">
<input class="input-btn" type="submit" value="Save" name='submit_assigned_users_form'>
</div>
</form>
Essentially, this code looks at the checkbox widget iteration (user) and gets the value, passes that value to the template tag and then returns the associated object back to the page.
Not the best solution given that you're repeating the query search for each object, rather than gathering them all in one go. But this is the best I could come up with.

How to change form layouts in Django 1.8

I have a form
Field Name: [Input Box]
I want
Field Name:
[Input Box]
How can I achieve this?
forms.py
class SearchForm(forms.Form):
search = forms.CharField()
views.py
form = SearchForm()
html_dtc = {'form':form}
return render_to_response('site/home.html', html_dtc)
home.html
<form method='POST' action=''> {% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
Thank you :)
You want a custom form rendering. You can read more about it here. For example, the following code would achieve what you're after.
<form method='POST' action=''> {% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} <br/>
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
(field.errors are added, because when you are manually rendering the form, you have to take care of error rendering as well)
Try to overide form.as_p()
class SearchForm(forms.Form):
search = forms.CharField()
def as_p(self):
"Returns this form rendered as HTML <p>s."
return self._html_output(
normal_row='<p%(html_class_attr)s>%(label)s <br> %(field)s%(help_text)s</p>',
error_row='%s',
row_ender='</p>',
help_text_html=' <span class="helptext">%s</span>',
errors_on_separate_row=True)
If this is a one off thing you can render your form manually like described here in the documentation.
Otherwise there's the django-floppyforms which gives you great control over how forms and (default) widgets are rendered.
Just define a custom layout, make it the default, use floppyforms custom Form classes (they behave exactly the same) and you're good to go.
As far as I remember some of floppyforms's functionality will also be included in Django 1.9, so look out for that, too.
Use django_crispy_forms: http://django-crispy-forms.readthedocs.org/en/latest/
In the template include {% load crispy_forms_tags %} and for the form:
{% crispy form %}
In addition, you can change the layout of the form easily, by overriding the form_class in the init function of the form:
class ContactForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_class = 'form-horizontal' # <-- leave out for vertical, or form-inline
self.helper.render_hidden_fields = True
self.helper.layout = Layout(
Div(InlineRadios('applying_for_whom'), css_class="col-xs-12"),
Div(InlineRadios('gender'), css_class='col-xs-12'),
Div('agreed_to_data_transmit', css_class="col-xs-12"),
As a bonus, if you are using bootstrap, set also set CRISPY_TEMPLATE_PACK = 'bootstrap3' so then everything is taken care of automatically for vertical bootstrap.
you can do
<form method='POST' action=''>
{% csrf_token %}
<label>Field Name:</label>
{{ form.search }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
generally I don't recommend use the HTML code generated by Django, but instead I supply what is needed by the DJANGO form.
but some are required: like the ERRORs, like the CSRF token.
let me add some examples to clarify what I am talking
<form class="*" style="*">
<label /><input name="email" />
<label /><input name="password" />
<form>
basically what I am suggesting is, do not use template tags unless absolute necessary like CSRF.
in this way, you can completely separate the design from the backend logic. you can have front end work indecently on the UI. the interface is the form fields, you have to supply all fields to the backend. like in this case 'email' && 'password' is required at backend

Using modelForm hidden field with Formsets without using Crispyform.

I am working with forms sets, I was wondering how one could use
<input type='hidden'
inside a form set. (Django formsets allow us to use multiple forms instances of a single form)
Its easy to do in normal single form where you just put the field with the type='hidden' and name='fieldname' e.g.
<input type='hidden' name='user' value='{{request.user.id}}'>
Dealing with formsets is a bit catchy, how to achieve the same behavior with the forms sets?
Views.py
PictureFormSet = modelformset_factory(Picture, form=UpdatePictureForm, extra=0)
formset_qset = Picture.objects.filter(id__in=[15, 16, 17, 18, 19, 20])
if request.method == POST:
ctx['form_set'] = PictureFormSet(request.POST, queryset=formset_qset)
ctx['form_set'].save()
ctx['form_set'] = PictureFormSet(queryset=formset_qset)
return render_to_response('temp tabs.html', context_instance=RequestContext(request, ctx))
Template
<form method="POST" action="" class="form-horizontal">
{% for form in form_set %}
{{form.id}}
<div class="form-group">
<label class="col-lg-2 control-label">
{% with form.meta_data.value|load_meta_data as meta %}
<div class="portfolio-item video-container">
<a class="" href="{% url 'view_image' form.id.value %}?in=pro">
<i style="background-image: url({{ meta.image_size.thumbnail_small }});"
class="ds-thumbnail-container"></i>
</a>
</div>
{% endwith %}
</label>
<div class="col-lg-8 ">
{{ form.name }}
</div>
</div>
{% endfor %}
{{ form_set.management_form }}
{% csrf_token %}
<input type="submit" value="Submit">
</form>
Explanation
Here in this code, We are rendering images from the database for editing there names. we have url information inside the meta_data, so we have selected
fields=['id', 'meta_data', 'name']
We want to change/Update the name, but not the meta_data
This code works fine for the most part, but how i want to keep one field unchanged for the modal?
I have meta_data field that I am using in the template, but i do not want that field to be modified, that value should be in the form like this
{{form.meta_data}}
This turns it into text area, with different name and id. and it expects it be changing. but i want to declare a hidden field and sets its value to the form.meta_data.value
If you have any questions regarding this please do not hesitate to ask.
Thanks.

Setting ID for Radio buttons in Django

It is great that Django 1.4 allows fine graining of radio select
{% for radio in form.important_client reversed%}
{{radio.tag}}<label for="????">{{radio.choice_label}}</label>
{% endfor %}
but for some odd reason when using this methodology, the <input> have no IDs. And hence I can't set the <label for='ID' /> accordingly. That causes big issues in my CSS.
Is there anyway to get the IDs set nonetheless?
While debuging a RadioSelect rendering, I got no idea of using radio tag and label elegantly. So here is my attempt to solve your problem:
{% for radio in form.important_client reversed %}
<input name="{{ radio.name }}" type="radio" id="radio_{{ radio.index }}" value={{ radio.choice_value }}>
<label for="radio_{{ radio.index }}">{{ radio.choice_label }}</label>
{% endfor %}
Instead of radio.index property, which is not documented, you can use forloop.counter.
Just in case I attach a screenshot of debug window, where example of radio context is shown (form_of_field variable on a figure):
This is one way to do that, it might not be the best but it works. In your form you can set the id for each of the choices like this:
from django import forms
class MyForm(forms.Form):
CHOICES = (('1','Available'),('2','Not Available'))
input = forms.ChoiceField(widget=RadioSelect(attrs={'id' : 'myId'},choices=CHOICES)
Then on your template:
{% for radio in form.input %}
{{ radio }}
{% endfor %}
And your HTML will look like this:
<label for="myId_0"><input id="myId_0" name="input" type="radio" value="1"></label> Available
<label for="myId_0"><input id="myId_0" name="input" type="radio" value="2"></label> Not Available
I hope this works!

Django identifying non field validation error is associated with which form

Is there a way to identifying the validation error is associated with which form for a template contaning multiple forms?
Let me explain the scenario. I have login window popup script within my base.html
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>{% csrf_token %}
<div class="d-header">
{{ form.non_field_errors }}
<input type="text" name="username" id="id_username" value="" onclick="this.value=''"/><br/>
<input type="password" name="password" id="id_password" value="" onclick="this.value=''"/><br/>
<input type="hidden" name="login_form" value="1" />
<input type="submit" value="login" />
</div>
{% endif %}
</div>
</form>
</div>
<div id="mask"></div>
{% if form.non_field_errors %}
<script>
var maskHeight = $(document).height();
var maskWidth = $(window).width();
//Set heigth and width to mask to fill up the whole screen
$('#mask').css({'width':maskWidth,'height':maskHeight});
$('#mask').show();$('.window').show();
</script>
{% endif %}
As all other templates extends base,html whenever there is an error non_field error then login window pops up . I would like to show the login error only when login form is submit not on submit of someother form with a non field error.
For this I need to identify the name of the form.something like this {% ifequal form.form_name login_form %} - Display login error .Is this possible??
They isn't anything special about the name 'form' in the template. It's just a default context name, you can choose to name your forms anything you like.
Just name the forms differently in your context:
from django.http import Http404
def detail(request, poll_id):
# NOTE: This view code isn't really form processing code, just using it to show
# how you can pass different names into your template context.
login_form = MyLoginForm()
detail_form = MyDetailForm()
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', {'poll': p, 'login_form': login_form, 'detail_form': detail_form})
And then:
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>
{% csrf_token %}
<div class="d-header">
{{ login_form.non_field_errors }}
.
.
.
Also, if you want to do multiple instances of the same form type, have a look at formsets