I have a simple ChoiceField and want to access the 'selected' item during my template rendering.
Lets say the form gets show again (due to error in one of the fields), is there a way to do something like:
<h1> The options you selected before was # {{ MyForm.delivery_method.selected }} </h1>
(.selected() is not working..)
Thanks !
#Yuji suggested bund_choice_field.data, however that will return value which is not visible to user (used in value="backend-value"). In your situation you probably want literal value visible to user (<option>literal value</option>). I think there is no easy way to get literal value from choice field in template. So I use template filter which does that:
#register.filter(name='choiceval')
def choiceval(boundfield):
"""
Get literal value from field's choices. Empty value is returned if value is
not selected or invalid.
Important: choices values must be unicode strings.
choices=[(u'1', 'One'), (u'2', 'Two')
"""
value = boundfield.data or None
if value is None:
return u''
return dict(boundfield.field.choices).get(value, u'')
In template it will look like this:
<h1> The options you selected before was # {{ form.delivery_method|choiceval }} </h1>
UPDATE: I forgot to mention an important thing, that you will need to use unicode in choice values. This is because data returned from form is always in unicode. So dict(choices).get(value) wont work if integers where used in choices.
It would be accessed by {{ myform.delivery_method.data }}
<h1> The options you selected before was # {{ MyForm.delivery_method.data }} </h1>
Related
Suppose in views.py I have a variable (i.e., changing) number of forms or types of objects in my context. (I'll just use the word 'forms' for simplicity).
context = {
'form_0': form_0,
'form_1': form_1,
'form_2': form_2,
'form_3': form_3,
# ... and so forth
}
Let's suppose that I have no way of knowing how many forms are in my context at any given time. Is it at all possible to do the following with template tags:
{% for i in (number of forms in context) %}
{{ form_i }} <-- where i is equal to the number i in the loop -->
{% endfor %}
Here the end result would translate to:
{{ form_0 }}
{{ form_1 }}
{{ form_2 }}
... and so forth
I'm doubtful that this is at all possible, but if it is, I would find it quite helpful.
Referencing by name, as in constructing a string that contains the name, is usually considered an unsafe approach: it can be harder than one thinks to make an algorithm that constructs the name correctly. Forthermore say that you do that and later remove form_3, then your algorithm will likely stop at 2, but perhaps there are still other forms there, but you forgot about the algorithm fetching the forms.
It is better here to pass a collection of objects, for example a list:
context = {
'forms': [form_0, form_1, form_2, form_3]
}
then we can render this in the template with:
{% for form_i in forms %}
{{ form_i }}
{% endfor %}
If you thus add an extra form to the list, then that form will be part of the iterations in the template, and thus Django will render that form (or whatever you put in the list).
If you need acces to some specific forms as well, you can pass then trhough another name as well, for example:
context = {
'forms': [form_0, form_1, form_2, form_3],
# if we need specific items of form_2 in the template,
# we can pass it under a specific name as well
'form_2': form_2
}
so now we can both enumerate over the forms to render these, but if form_2 has some interesting data we need to handle in the template as well, we can still use {{ form_2.non_field_errors }} for example.
I need a way to set the id of the div that contains each form in a formset to a value that contains a number that is representative of the index of that form.
eg. I want the 2nd form to have a parent div that looks like this
<div id="1"> #id could even be "id_form-1-id".
form
</div>
I've found that {{form.id}} produces the following:
<input type="hidden" name="form-3-id" id="id_form-3-id">
Is there a way that I can extract just the id value (i.e. id_form-3-id) from this string using a template tag?
For reasons that I won't get into, a forloop.counter counter won't reliably return an index as some forms within the formset can be created outside of the typical formset for loop.
Thanks!
You can use auto_id:
{{form.id.auto_id}}
I am trying to pass full object instances from my django template to my view as the values associated with checkbox inputs. When I try to do so, I only get the object's unicode method representation and am thus unable to access any of the object's particular fields in my view.
Is there either a way to pass the actual object from the template to the view or, instead, a way to use that unicode representation in the view to access the actual object and its corresponding fields?
I don't want to use 'publication.id' as my checkbox value because I can't guarantee the ids will never change.
Current code:
mytemplate.html
<form method="get" action="processData">
{% for publication in mydata %}
<input type="checkbox" name="item-selection" value="{{publication}}">
{% endfor % }
view.py
items = request.GET.getlist('item-selection')
for x in items:
print x # this prints the unicode mehtod's return value
x.datafield1 # I want to access each object's data
No, this can't possibly work: sending data from the browser to the view is done via HTTP post, and you can only post data, you can't post objects.
But you've said the solution yourself: use the IDs. Who cares if the IDs change? All that matters is that you get the ID as it currently is.
<input type="checkbox" name="item-selection" value="{{publication.id}}"><label>{{ publication.name }}</label>
...
item_ids = request.GET.getlist('item-selection')
items = Item.objects.filter(id__in=item_ids)
I have a ModelChoiceField and a ChoiceField that I need to pull out the "display name" for (not the "value").
For example, a ModelChoiceField of a form renders the following output:
<select name="amodelfield" id="id_amodelfield">
<option value="">---------</option>
<option selected="selected" value="1">ABC</option>
<option value="2">DEF</option>
</select>
I want to be able to just render "ABC" since it is selected. If I do {{ field.value }} as said in the docs, I get the value 1 instead of the ABC I wanted. I also have a ChoiceField for which I want the same behavior.
Is there a easy way to do this without subclassing ModelChoiceField, ChoiceField and the Select widget?
EDIT: Model.get_FOO_display() would not work in this case
Use {{ get_fieldname_display }} for it.
https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_FOO_display
From the link that #Odif Yltsaeb provided, I was able to use modify the code from the answer to work generically for my needs. Here's the code for reference:
def choiceval(boundfield):
"""
Get literal value from field's choices. Empty value is returned if value is
not selected or invalid.
Important: choices values must be unicode strings.
choices=[(u'1', 'One'), (u'2', 'Two')
Modified from:
https://stackoverflow.com/a/5109986/2891365
Originally found from:
https://stackoverflow.com/questions/19960943/django-rendering-display-value-of-a-modelchoicefield-and-choicefield-in-a-templ
"""
# Explicitly check if boundfield.data is not None. This allows values such as python "False"
value = boundfield.data if boundfield.data is not None else boundfield.form.initial.get(boundfield.name)
if value is None:
return u''
if not hasattr(boundfield.field, 'choices'):
return value
return dict(boundfield.field.choices).get(value, u'')
For some reason I use a custom HTML-code for displaying the form. My form's input get the initial value (date), and shows the same form after submittion.
But after submit, input has no previously selected value (just empty).
I use {{ Form.Fileld.value|date:"Y-m-d" }} in the temlate to get initial and submitted values.
It seems that initial and submitted values are in different formats: "datetime" for initial values and "string" after submit.
Here is my simple test:
Form
class ShowStartEndDateForm(forms.Form):
start_date = forms.DateField(initial=date.today().replace(day=1),
label="Start",
widget=forms.DateInput(format='%Y-%m-%d'),
input_formats=['%Y-%m-%d'])
...
View
if request.method == 'POST':
form_date = ShowStartEndDateForm(request.POST)
if form_date.is_valid():
form_was_submitted = True
cd = form_date.cleaned_data
operator = cd['operators']
days=[]
for day in range(0,(cd['end_date']-cd['start_date']).days+1):
days.append(cd['start_date']+relativedelta(days=+day))
else:
form_date = ShowStartEndDateForm()
return render_to_response('epay.html', locals(),
context_instance=RequestContext(request))
Template
<!- HTML FORM here
|classname is my custom template filter.
-->
Date1: {{ form_date.start_date.value|date:"Y-m-d" }} \
({{ form_date.start_date.value|classname }})
Date2: {{ form_date.start_date.value }}
First call in browser:
Date1: 2013-10-01 (date)
Date2: 1 October 2013
After form submit:
Date1: (unicode)
Date2: 2013-10-01
What am I doing wrong? What is the proper way to access form's field initial and submitted values?
Thnak you.
You're question is a bit confusing (you should add some more of your actual code), but I know from experience that when mixing between formats, its a good convention to just do it all in one place. So instead of specifying the format on the client side like you do, specify it all on the form itself and then everything would (should) be in-sync.
class ShowStartEndDateForm(forms.Form):
start_date = forms.DateField(initial=date.today().replace(day=1),
label="Start",
widget=DateInput(format='%Y-%m-%d'),
input_formats=['%Y-%m-%d'])
i.e. you tell the the DateInput widget what form to take and you tell input_formats (for the field itself) what formats to expect (you can add more than one). Also, if you are using some sort of datepicker you of course need to make sure it is also using the right format.
Edit
I replicated this and everything was fine:
In [1]: from test.forms import *
In [2]: f = ShowStartEndDateForm()
In [3]: print f
<tr>
<th><label for="id_start_date">Start:</label></th>
<td><input id="id_start_date" name="start_date" type="text" value="2013-10-01" /></td>
</tr>
(of course I changed the indentation here so you could see it more clearly)