Django accessing form fields dynamically in template - django

I am trying to mimic the django admin's fieldsets functionality, to group form fields in my own view.
So I have a form in my template, and I have passed the fieldset list in my context data.
{% for fieldset in fieldsets %}
<fieldset class="module aligned">
<h2>{{ fieldset.0 }}<h2>
{% for field in fieldset.1.fields %}
<div>
{{ form.field }}
</div>
{% endfor %}
</fieldset>
{% endfor %}
The problem is the {{ form.field }} is treating field as a string, and not as the value stored in the variable. Is there a way to access this in the template, like getattr().

Related

Accessings fields directly in Django adminform template?

I have a ton of fields that I need to layout (reorder) in a specific way the form (with some other extra html stuff). I created change_form.html file for my model, which itself works.
The problem is all examples are looping over the fields, I just want to refer to each field by name.
# this works
{% for fieldset in adminform %}
{% for line in fieldset %}
{% for field in line %}
<p>{{ field.field }}</p>
{% endfor %}
{% endfor %}
{% endfor %}
I know you can customise the admin.ModelAdmin with fieldsets, etc.. But that's not what I want.
I was trying different ways like below, but it doesn't work:
# assuming the admin model has the fields: first_name & last_name
{% block content %}
<!-- doesn't work !!! ->
{{ adminform.fieldsets.0.1.fields.first_name.field }}
{{ adminform.fieldsets.0.1.fields.last_name.field }}
<!-- neither does this -->
{{ adminform.fields.first_name.field }}
{{ adminform.fields.last_name.field }}
{% endblock %}
Now this doesn't work, is there any efficient way to directly access the fields I need?
I was looking in the complete wrong direction. Its actually super simple, you can use it as follows.
When you have model with a field last_name you can access the field:
# change_form.html (custom)
{% extends "admin/change_form.html" %}
{% block field_sets %}
# get the label
<label for="{{ adminform.form.last_name.label }}">
{{ adminform.form.last_name.id_for_label }}
</label>
# get the html widget
{{ adminform.form.last_name }}
# get the field value
{{ adminform.form.last_name.value }}
# create your own input (without the label)
<input name="{{ adminform.form.last_name.html_name }}">
# some other fields you can reference
{{ adminform.form.last_name.max_length }}
{{ adminform.form.last_name.required }}
{{ adminform.form.last_name.help_text }}
{{ adminform.form.last_name.label_suffix }}
{% endblock %}
U can create a ModelForm to be used in your ModelAdmin, check de docs -> https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
another way could be setting fields tuple, docs here -> https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fields
Hope this drives U in the right path.

django templates: How to know form field type and add any buttons based on field type

I am displaying my django forms dynamically with below code.
{% for field in form %}
{% if field.field.required %}
<span class="red">*</span>
{% endif %}
{{ field.label }}:
{{ field }}
{% endfor %}
Now I want to know the datatype of fields.if field type is Datetimeinput then I want give one button beside to it to get JavaScript calender.
i want do like as below but I am not able get it
{% for field in form %}
{% if field.field.required %}
<span class="red">*</span>
{% endif %}
{% if field.field_type == 'Datetimeinput' %}
{{ field.label }}:
{{ field }}
<label>From :</label><input type="text" name="from1" class="txtbox"><input type="button" value="Cal" onclick="displayCalendar(document.forms[0].from1,'yyyy-mm-dd',this)">
{% else %}
{{ field.label }}:
{{ field }}
{% endif %}
{% endfor %}
Help me out thanks in advance.
Make a template tag. Depending on Get type of Django form widget from within template. I used this solution once or twice.
from django import template
register = template.Library()
#register.filter('klass')
def klass(ob):
return ob.__class__.__name__
In template:
{{ field.field.widget|klass }}
Will return field class name to be used in your if statements.
You could write a custom template filter for that.
#register.filter
def fieldtype(obj):
return obj.__class__.__name__
Docs on custom filters: link
However, why not just render fields without looping over them?
{{ form.birthdate }}
Then you'll know for sure what is what.

Django: For Loop to Iterate Form Fields

I don't want to use django's built in form generation, seeking to specify each field in my template in order to customize the html output.
How do I iterate over a series of form fields?
If my form looks like this:
class MyForm(forms.Form):
main_image = forms.ImageField()
second_image = forms.ImageField()
third_image = forms.ImageField()
fourth_image = forms.ImageField()
...
Is there way to write a {% for %} loop so that I can iterate through:
{{ form.main_image }}
{{ form.second_image }}
{{ form.third_image }}
{{ form.fourth_image }}
I tried the following which seemed logical, but did not work:
{% for field in form %}
{{ form.field }}
{% endfor %}
Well this would clearly not work:
{% for field in form %}
{{ form.field }}
{% endfor %}
but this will:
{% for field in form %}
{{ field }}
{% endfor %}
The best way is to use two loops, one for hidden fields and one for visible fields :
visibles:
{% for field in form.visible_fields %}
{{ field.label }}
{{ field }}
{% endfor %}
hiddens:
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
in this way you will have better control over UI elements.
This one should work :
{% for field in form %}
{{ field }}
{% endfor %}
Once you loop through field in form , you can't access form.field
For any frontend developers looking to customize a Django form you can use a package called django-widget-tweaks to render fields individually. Example code below:
{# Your template with the form #}
{% extends "base.html" %}
{% load widget_tweaks %}
<form action="" method="POST">
{% csrf_token %}
{% for field in form %}
<label for="{{ field.id_for_label }}">
{{ field.label }}{% if field.field.required %}*{% endif %}
</label>
{% render_field field %}
{% endfor %}
<button type="button">
Submit Form
</button>
</form>
Note: You'll want to make this look nicer of course, and you may want to loop through your form errors if there are any.
They have some very useful examples on their PyPi page as well.

Trying to access ModelForm field modelChoice choices in Django template

I'm generating ModelForms and want some granular control over how they are output in my template. Specifically, I need to add some markup to the end of each radio button in each of my select lists.
Code:
# order-form.html
{% load catname %}
<form id = "order-form">
{% for form in forms %}
<div id="gun-{{ forloop.counter }}">
{% for field in form.fields %}
<div id="{{ field }}-item" class="item">
<h3>{{ field|catname }}</h3>
{% for choice in form.field.choices %} {# <-- Help me out here #}
{{ choice.id }}
{{ choice.title }}
{% endfor %}
</div>
{% endfor %}
{% endfor %}
<button type="submit" id="standard-gun-form-submit">Continue to next step</button>
</form>
# views.py
def get_form(request):
if request.method == 'POST':
if request.POST['gun_type'] == 'standard':
forms = [StandardGunForm(prefix=p) for p in range(0,2)]
return render_to_response('main/order-form.html', {'forms' : forms,}, RequestContext(request))
# forms.py
class StandardGunForm(ModelForm):
def __init__(self, *args, **kwargs):
super(StandardGunForm, self).__init__(*args, **kwargs)
for field in self.fields:
if isinstance(self.fields[field], ModelChoiceField):
self.fields[field].empty_label = None
class Meta:
model = BaseGun
widgets = {
'FrameTuning' : RadioSelect(),
'FrameConnection' : RadioSelect(),
}
exclude = ('price')
Endgame: markup that looks like this
<form id="foo">
<div class="category">
<div class="item">
<input type="radio" name="srsbzns" value="1">Option 1</input>
<img src="http://placekitten.com/150/150">
<p>Other foo here</p>
</div>
<div class="item">
<input type="radio" name="srsbzns" value="2">Option 2</input>
<img src="http://placekitten.com/150/150">
<p>Other foo here</p>
</div>
<div class="item">
<input type="radio" name="srsbzns" value="3">Option 3</input>
<img src="http://placekitten.com/150/150">
<p>Other foo here</p>
</div>
</div>
</form>
From the shell, this returns what I want
>>> forms = [StandardGunForm(prefix=p) for p in range(0,2)]\
>>> forms[0].fields['frame_tuning'].choices.queryset
I'm surprised this is proving so challenging!
Bonus: I have DEBUG = True and Django Debug toolbar enabled. Is it possible to dump the variables to the browser, so I can see what this stuff looks like as I drill down?
Thanks!
I had to do something similar and started down this path as well. I wanted to create table rows from a ModelChoiceField where each column had a different field of the model instance (and then I'd allow filtering the table rows via JavaScript).
I couldn't find it in the Django docs, but a quick perusal of the Django source showed the way. You can get to the queryset to access the model instances like so:
<form action="{% url 'some_view' %}" method="post">
{% csrf_token %}
{% if form.non_field_errors %}
{{ form.non_field_errors }}
{% endif %}
{% for field in form %}
{{ field.label }}
{% if field.field.choices %}
{% for model_instance in field.field.choices.queryset %}
{{ model_instance.id }}
{% endfor %}
{% else %}
{{ field }}
{% endif %}
{% if field.errors %}
{{ field.errors|striptags }}
{% endif %}
{% endfor %}
<button type="submit">Submit</button>
</form>
However, at this point we've disassembled the shiny widget (in my case a CheckboxSelectMultiple) and must re-assemble the HTML form input using template code. I found no direct way to simultaneously iterate over the ModelChoiceField to access the model instance fields and get the HTML form tags for the choices.
Maybe there's a way, but I abandoned my attempt and built my own HTML form, handling all the POST data in a view. It ended up much easier that way. ModelForms are really nice and convenient, but using them for something they weren't built for can end up being more difficult.
I figured I'd post this in case anyone is trying to do it for some other reason. Hope it helps.
Very late, but I'm reading now and this is what it worked for me
{% for field in form %}
{% for x, y in field.field.choices %}
{{x}}
{{y}}
{% endfor %}
{% endfor %}
Where "x" is the id or code, and "y" is the readable value or title.
You can access the underlying model instance for each choice:
{% for choice, label in form.field_name.field.choices %}
{{ choice.value }}
{{ choice.instance }}
{{ choice.instance.instance_attribute }}
{{ label }}
{% endfor %}
{% for choice in form.field.choices %} {# <-- Help me out here #}
{{ choice.id }}
{{ choice.title }}
{% endfor %}
Look what you're doing here, you're literally trying to access a field called "field" every time in this loop, which presumably does not exist.
You need to take the field object you're iterating through, and access the choices attribute on that.
{% for field in form.fields %}
{% for choice in field.choices %}

django change form field in .html template output

I create a form based on a model , like seen below:
class ContactSelectionForm(forms.ModelForm):
contacts = ManyToManyByLetter(Contact, field_name="first_name")
class Meta:
model = ContactSelection
exclude = ('created_by',)
When I process this view I see at the .html output a field labeled with "Contact".
Now I`m wondering whether it is possible to change this output. For example I want to name this field not "Contact" but "Selected Contacts".
This is the form processing part of the .html template:
<form action="{{ request.path }}" method="POST">
<div>
<fieldset class="module aligned">
{% for field in form.visible_fields %}
<div class="form-row">
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Save" /></p>
</fieldset>
</div>
</form>
If somebody is wondering what ManyToManyByLetter(Contact, field_name="first_name") in the form is, check out http://code.google.com/p/django-ajax-filtered-fields/ . A very helpful many2many javascript library.
Did you try setting the fields label?
(the docs)
contacts = ManyToManyByLetter(Contact, field_name="first_name", label="Selected Contacts")