Get key, value pair from Django object in template - django

How do I get key,value pair from object from get_object_or_404 in template, passed from view to template as context?
#views.py
def detail(request):
unknown = get_object_or_404(UnknownModel)
return render(request, 'app/display.html', { 'some_data':unknown })
and in app/display.html, I've been trying various approaches:
{{ some_data }}
{{ some_data.keys }}
{{ some_data.items }}
{% for key, value in some_data.items %}
{{ key }} - {{ value }}
{% endfor %}}
but none work.
If I knew the fields, I can access easily as below, but that's not the case
{{ some_data.field_1 }}

In your case unknown is instance of UnknownModel model.
In template, you are trying to iterate over this instance fields, but items method works
for dictionaries, not for your model. You can provide items method in your model to return dictionary with fields that you want or use following snippet:
{% for key, value in some_data.__dict__.items %}
{{ key }} - {{ value }}
{% endfor %}}
Method above will display many internal data related to your instance. Another (better) way of doing this is to convert your model instance to the dictionary inthe view and then pass it to the template. To achieve that, you can use django.forms.models.model_to_dict method.
from django.forms.models import model_to_dict
def detail(request):
unknown = get_object_or_404(UnknownModel)
return render(request, 'app/display.html', {'some_data':model_to_dict(unknown)})

Related

Django: how to display my own dynamically-made fields

I have a SurveyForm where I create dynamically my fields. Here's the most basic code I could do and still have my problem:
class SurveyForm(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields = []
self.fields_alone = []
new_field = forms.CharField(label=f'1 - 2: This is the question',
widget=widgets.Input(attrs={}))
self.fields.append(('id_1', new_field))
self.fields_alone.append(new_field)
self.fields = OrderedDict(self.fields)
In my template, when I do a "classical" loop I can display the fields and it works, but the second loop, which is supposed to access to the same fields, doesn't work:
<form action="" method="post">
{% for field in form %}
{{ field.label }} :{{ field }} <br>
{% endfor %}
{% for field in form.fields_alone %}
{{ field.label }} :{{ field }} <br>
{% endfor %}
</form>
The second loop display the field as a string like <django.forms.fields.CharField object at 0x0000012C00EF60D0>
What am I missing to display is like the "classical" loop?
I found the problem. It's in the source code of Django.
Django can only convert fields to HTML if they are BoundField. The problem is that you can access to the BoundField "version" of the fields of your form through iteration on the form itself.
In the django/forms/forms.py:
def __getitem__(self, name):
# blabla code
if name not in self._bound_fields_cache:
self._bound_fields_cache[name] = field.get_bound_field(self, name)
So you can get HTML code only through an iteration on the form or direct access to a field via form['myfield'].
So in my form I did:
class SurveyForm(forms.Form):
def field_by_id(self, field_id):
return self[field_id]
Then I've made a template tag in my application which is:
#register.filter(name='field_by_id')
def field_by_id(arg1, arg2):
"""
Returns the result of field_by_id() (= method has to exist in arg1!)
Usage: {{ form|field_by_id:XXX }} (XXX = field id string)
:param arg1: object of class Form
:param arg2: field id string
:returns corresponding field
"""
return arg1.field_by_id(arg2)
and then in my template, I use it like this:
{% for question_group, questions in form.question_groups.items %}
{% for question, answers in questions.items %}
{% for answer in answers %}
{% with form|field_by_id:answer as field %}
{{ field.label }} :{{ field }} <br>
{% endwith %}
{% endfor %}
{% endfor %}
{% endfor %}
And it works. Tricky solution, but I have many sub-groups (I could have used FormSet's for a single sub-group).
The fields list is meant to store the form fields. Whereas fields_alone isn't.
That is also the reason why you are able to loop over the form itself and not over form.fields.
Since I cant figure out why you need to have this other list I suggest that you add all the fields to the actual fields list.
Comment if there are any further questions to this problem
Here:
self.fields = []
You're overwriting the form's own fields ordereddict. You just want to add to it:
self.fields["whatevernameyouwant"] = new_field
(works on django 1.11, not tested on 2.x / 3.x)
EDIT:
the problem is when I try to use the fields through another property
You mean the form.fields_alone thing ? Well, you can always make it a property instead:
class YourForm(...):
def __init__(...)
# ....
self._fields_alone = []
self.fields["whatevernameyouwant"] = new_field
self.fields_alone.append("whatevernameyouwant")
#property
def fields_alone(self):
for name in self._fields_alone:
yield self[name]
But it won't remove this field from the "normal" form iterator (for field in form) so you'll have the field twice, so you'd also need to redefine __iter__ too:
def __iter__(self):
for name in self.fields:
if name not in self._fields_alone:
yield self[name]

How to access field values of an object from a ModelMultipleChoiceField, from within a template?

I have a database of television channels that I am displaying using a Django form with a ModelMultipleChoiceField and a CheckboxSelectMultiple widget.
The template renders fine, but how do I access fields of the individual objects that are part of the ModelMultipleChoiceField field of the form?
Channel model
class Channel(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
This is the form
class ChannelForm(forms.Form):
channels_list = forms.ModelMultipleChoiceField(queryset=Channel.objects.all().order_by('name'),widget=forms.CheckboxSelectMultiple)
This is how I was trying to access the 'name' field of each channel in the template by doing {{channel.name}}.
{% for channel in form.channels_list %}
{{ channel }} accessing: {{ channel.name }}<br>
{% endfor %}
When it renders it simply says "accessing: " without the channel name
Here is my view.py as requested:
def generage_recommendation(request):
if request.method == 'POST':
# POST code ...
else:
form = RecommendationRequestForm()
return render(request, 'recommendation_home.html', {'form':form})
in your views.py,
use ChannelForm instead of RecommendationRequestForm.
in your template, you can access field values of ModelMultipleChoiceField like this:
{% for key, value in form.channels_list.field.choices %}
Channel ID = {{ key }}
Channel Name = {{ value }}
{% endfor %}
(notice .field. code)
Can you post your views.py file.
You don't have to use
form.channels in the template.
Try using this instead.
{% for channel in channels_list %}
{{ channel }} accessing: {{ channel.name }}<br>
{% endfor %}

Accessing dictionary within url tag (Django)

I have the following Jinja code for my Django application:
<ul>
{% for key, value in course_avrg.items %}
<li>
{{ key }}: {{ value }}
</li>
{% endfor %}
</ul>
The course_ids is a dictionary with key course name (str) and value course id (int).
The course_avrg is another dictionary with key course name (str) and value course average (int)
In the above code, I'm trying to get the primary key value (int) of each course by passing the course name "key" into course_ids dictionary.
However, I get the following error:
Could not parse the remainder: '[key]' from 'course_ids[key]'
so how should I access dictionary value from within the Jinja URL tag?
You can write custom template filter:
#register.filter
def getvalue(dict, key):
return dict[key]
And use it in template like this:
{{ key }}: {{ value }}

ModelMultipleChoiceField dosen't work correctly in django form

I need a combobox in my template. so I use ModelMultipleChoiceField when I try to submit my form It said this field is empty and you must choose !
myform:
class SearchForm(forms.Form):
type_pm = forms.ModelMultipleChoiceField(queryset=IvrModel.objects.all(), widget=forms.Select())
my template:
{% for field in form %}
{{ field.label_tag }}
{{ field }}
{% endfor %}
how do I fix It?
Remove widget=forms.Select(). ModelMultipleChoiceField expects list of values, not a single value.

Django templates: value of dictionary key with a space in it

In a Django template, is there a way to get a value from a key that has a space in it?
Eg, if I have a dict like:
{"Restaurant Name": Foo}
How can I reference that value in my template? Pseudo-syntax might be:
{{ entry['Restaurant Name'] }}
There is no clean way to do this with the built-in tags. Trying to do something like:
{{ a.'Restaurant Name'}} or {{ a.Restaurant Name }}
will throw a parse error.
You could do a for loop through the dictionary (but it's ugly/inefficient):
{% for k, v in your_dict_passed_into_context %}
{% ifequal k "Restaurant Name" %}
{{ v }}
{% endifequal %}
{% endfor %}
A custom tag would probably be cleaner:
from django import template
register = template.Library()
#register.simple_tag
def dictKeyLookup(the_dict, key):
# Try to fetch from the dict, and if it's not found return an empty string.
return the_dict.get(key, '')
and use it in the template like so:
{% dictKeyLookup your_dict_passed_into_context "Restaurant Name" %}
Or maybe try to restructure your dict to have "easier to work with" keys.
You can use a custom filter as well.
from django import template
register = template.Library()
#register.filter
def get(mapping, key):
return mapping.get(key, '')
and within the template
{{ entry|get:"Restaurant Name" }}