Trying to access ModelForm field modelChoice choices in Django template - django

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 %}

Related

Show / hide input field or div based on RadioField choice using Flask wtf_form

I am trying to build website using Flask, and can't find solution to one problem. I am trying to hide or show input field, based on RadioFeild choice. Also, if input field showing, it have to be required. I actually have everything working, besides knowing what RadioField choice was selected. I can see the form when loading page on 127.0.0.1:5000 and I can see RadioField with 2 choices: Yes and No, but when I click on yes, there are no changes, hidden input field is still not showing. Please, help!
app.py
class MyClass(FlaskForm):
my_field = RadioField("bla-bla-bla", choices=[('Yes', 'Yes'), ('No', 'No')], validators [InputRequired()])
#app.route("/some_page")
def some_page():
form = MyClass()
return render_template("some_page.html", form=form)
_render_field.html
{% macro render_radio_field(field) %}
<div class="form__item">
<label class="form__label">{{field.label.text }}</label>
<div class="form-group">
{{ field(class_='form__input', **kwargs)|safe }}
{% for subfield in field %}
<div class="form__item">
<label>
{{ subfield }}
{{ subfield.label.text }}
</label>
</div>
{% endfor %}
</div>
</div>
{% endmacro %}
some_page.html
{% from "_render_field.html" import render_field, render_radio_field %}
{% extends "layout.html" %}
{% block title %}My Title{% endblock %}
{% block content %}
<div style="width:600px; margin:0 auto;">
<h3>Some Text</h3>
<form class="form" action="{{url_for('some_page')}}" method="POST">
{% from "_render_field.html" import render_field, render_radio_field %}
{{ form.csrf_token }}
{{ render_field(my_field, title="", style="list-style:none") }}
{% if form.my_field.option == "Yes" %}
{{ render_field(form.some_other_StringField, placeholder="Please explain:", title="") }}
{% endif %}
<input type="submit" name="" value="login" class="form__btn">
</form>
</div>
{% endblock %}

Issue assigning form fields in the HTML template django

I have a model form and I wanted to know if it is possible to take a model form and assign the name of the specific field when it is running through a for loop within the template html file.
Here is what i have in the current html template:
{% extends "base.html" %}
{% block content %}
<h1>Add members to {{record.name}}</h1>
{% if message %}
<p>{{message}}</p>
{% endif %}
<form action="." method="POST">
{% csrf_token %}
{% for trans in transactions %}
{% if trans.record.id == record.id %}
{{ trans.user.username }}
{{ form.as_p }}
{% endif %}
{% endfor %}
<p>Tax: <input type="text" name="tax" value=""></p>
<p>Tip: <input type="text" name="tip" value=""></p>
<input type="submit" name="submit" value="submit">
</form>
{% endblock %}
here is the current form model:
class IndividualSplitTransactionForm(forms.ModelForm):
class Meta:
model = Transaction
fields = ['amount', 'description']
currently the format is looking like this:
omar
amount
description
hani
amount
description
assad
amount
description
tax
tip
so when i process it and i want to grab the amount assigned to each of the specific users and update a record. I want it to look something like this for easier processing in the view.
omar
omaramount
omardescription
hani
haniamount
hanidescription
assad
assadamount
assaddescription
tax
tip
so that when i am processing I can properly assign the corrent amount and description for each user when i am updating existing records with the amount.
is it possible to do that within the template itself or would i have to do it somewhere else.
UPDATED
So i tried to change my code and update it to get what i am trying to get but this is what i am getting...
Here is the html
{% extends "base.html" %}
{% block content %}
<h1>Add members to {{record.name}}</h1>
{% if message %}
<p>{{message}}</p>
{% endif %}
<form action="." method="POST">
{% csrf_token %}
{% for trans in transactions %}
{% if trans.record.id == record.id %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ trans.user.username }}{{ field.label }}{{ field|safe }}
</div>
{% endfor %}
{% endif %}
{% endfor %}
<p>Tax: <input type="text" name="tax" value=""></p>
<p>Tip: <input type="text" name="tip" value=""></p>
<input type="submit" name="submit" value="submit">
</form>
{% endblock %}
and here is what I am getting.
request returs
So if you look at the image, it is still just returning the last amount and description of the three that i entered... should i just create the whole form manually in the html file....
If you wanted the username + amount or username + description, then you to change away from form.as_p, because you will get the html <p><p/> tag for each field with label preceding it.
You want to dynamically add username then do by designing your own html content of the form manually.
There is a label_suffix, but prefix is not available. Even with suffix you should be doing it at the time of creating the form object.
Update:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ trans.user.username }} {{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}

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.

ListField is showing <ul> instead of <input> in edit/create post

I am using Flask, mongoengine for a project and I am trying to get basic stuff working from http://docs.mongodb.org/manual/tutorial/write-a-tumblelog-application-with-flask-mongoengine/
After implementing everything from above link I added a new field for "tags" in Post and when I try to create a post, my tags doesn't show a input box.
Any help is appreciated.
My code and screenshot below
class Post(db.DynamicDocument):
created_at = db.DateTimeField(default=datetime.datetime.now, required=True)
title = db.StringField(max_length=255, required=True)
slug = db.StringField(max_length=255, required=True)
comments = db.ListField(db.EmbeddedDocumentField('Comment'))
tags = db.ListField(db.StringField(max_length=30)) # New field I added
template form
{% macro render(form) -%}
<fieldset>
{% for field in form %}
{% if field.type in ['CSRFTokenField', 'HiddenField'] %}
{{ field() }}
{% else %}
<div class="clearfix {% if field.errors %}error{% endif %}">
{{ field.label }}
<div class="input">
{% if field.name == "body" %}
{{ field(rows=10, cols=40) }}
{% else %}
{{ field() }}
{% endif %}
{% if field.errors or field.help_text %}
<span class="help-inline">
{% if field.errors %}
{{ field.errors|join(' ') }}
{% else %}
{{ field.help_text }}
{% endif %}
</span>
{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
</fieldset>
{% endmacro %}
rendering form code
{% extends "admin/base.html" %}
{% import "_forms.html" as forms %}
{% block content %}
<h2>
{% if create %}
Add new Post
{% else %}
Edit Post
{% endif %}
</h2>
<form action="?{{ request.query_string }}" method="post">
{{ forms.render(form) }}
<div class="actions">
<input type="submit" class="btn primary" value="save">
Cancel
</div>
</form>
{% endblock %}
From what I can gather, your problem is you're telling WTF to render the tags field, but WTForms doesn't know how to handle that information.
From looking at the Flask-MongoEngine documentation, it seems the ListField is just a FieldList as WTForms refers to it.
Currently you're not actually defining the form independently in WTForms, you're just using the magic included in Flask-MongoEngine, so my first attempt would be to add some more logic to your macro, add a {% elif field.type == 'ListField' %} and try and discover what's contained in there to iterate through to produce your form. From having a quick look at the source-code, something like the following might work.
{% elif field.type == 'ListField %}
{# render_the_group_label #}
{% for subfield in field.entries %}
{% if subfield.type == 'StringField' %}
{# render_the_subfield #}
{% endif %}
{% endfor %}
...
That code will need to be worked on, but hopefully it'll point you in the right direction. Otherwise, I'd actually define the form seperately in WTForms to give you a bit more control on the code-side. Luckily they provide a csv tag example which should help you if you need to go that route. I wrote a guide that takes a different route using #property decorators to achieve a similar effect, which again, might at least point you towards the finish line.

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")