Django object is not iterable - django

I have a object that I'm trying to iterate over within my template.
My issue is that one of the fields response contains json data and I get this error message
transaction' object is not iterable
{% for item in transaction %}
{{ item.notjson_fields}}
{% for jsonItem in item.response %}
{{jsonItem}}
{% endfor %}
{% endfor %}
Model:
date_created = models.DateTimeField(auto_now_add=True)
request = JSONField()
response = JSONField()

You are trying to iterate over a Transaction object which is not iterable.
Try something like
{{ transaction.notjson_fields}}
{% for jsonItem in transaction.response %}
{{ jsonItem }}
{% endfor %}
I can't be sure though without knowing what Transaction looks like
Edit:
Since response is a JSONField, you can access it like a dict. Just do
{{ transaction.response.amount }}

If like Ngenator said, your field is not a JSON object but a string, you may need to load it first. First register a new template tag
from django import template
register = template.Library()
import json
#register.filter
def load_json(value):
return json.loads(value)
Then to get (just) the amount in your template
{% with transaction.response|load_json as jsondict %}
{% for k, v in jsondict.items %}
{% if k == "amount" %}
<td>{{ v }}</td>
{% endif %}
{% endfor %}
{% endwith %}
Good Luck.

Related

django ModelChoiceField: how to iter through the instances in the template?

I am trying to get access to the instances of a ModelChoiceField to render them the way I want in a template by displaying several fields of the instances.
class MyForm(forms.Form):
mychoices = forms.ModelChoiceField(
queryset=ObjectA.objects.all(), widget=forms.RadioSelect(), empty_label=None
)
This does not work:
{% for choice in form.mychoices %}
{{ choice.pk}}
{% endfor %}
I also tried to use the queryset but it does not render anything
{% for choice in form.mychoices.queryset %}
{{ choice.pk}}
{% endfor %}
Any idea?
Thanks
{% for choice in form.mychoices.field.queryset %}
{{ choice.pk }}
{% endfor %}
Notice the extra .field. It's a bit strange the first time you come across it, but it gives you what you want. You can also access the choices attribute of that object, instead of accessing queryset directly, but you'll need to access the first element of the choice to get the PK of the instance, like this:
{% for choice in form.mychoices.field.choices %}
{{ choice.0 }}
{% endfor %}

what is the right way to query a manytomany field in django

so i have a model which is,
class Category(SmartModel):
item=models.ManyToManyField(Item)
title=models.CharField(max_length=64,help_text="Title of category e.g BreakFast")
description=models.CharField(max_length=64,help_text="Describe the category e.g the items included in the category")
#show_description=check box if description should be displayed
#active=check box if category is still avialable
display_order=models.IntegerField(default=0)
def __unicode__(self):
return "%s %s %s %s " % (self.item,self.title, self.description, self.display_order)
and as you may see, it has a manytomany field
item=models.ManyToManyField(Item)
i want to return all the items in a template, here is my views.py for this
def menu(request):
categorys= Category.objects.all()
items= categorys.all().prefetch_related('item')
context={
'items':items,
'categorys':categorys
}
return render_to_response('menu.html',context,context_instance=RequestContext(request))
here is how am doing it in the templates,
<ul>
{% for item in items %}
<li>{{ item.item }}
</li>
</ul>
{% endfor %}
after all this,this is what it is returning in my web page,
<django.db.models.fields.related.ManyRelatedManager object at 0xa298b0c>
what am i doing wrong,I have really looked around but all in vain, hoping you can help me out and thanking you in advance
Exactly, you have a many to many manager. You need to actually query something... like all()
{% for item in items %}
{% for i in item.item.all %}
{{ i }}
{% endfor %}
{% endfor %}
Based on your variable naming, I think you're confusing the results of prefetch_related as a bunch of items. It is in fact returning a QuerySet of Category objects.
So it would be more intuitive to call them categories.
{% for category in categories %}
{% for item in category.item.all %}
{{ item }} {# ...etc #}
Try to use:
categorys= Category.objects.prefetch_related('item').all()
And then in template:
{% for category in categorys %}
{% for item in category.item.all %}
{{ item }}
{% endfor %}
{% endfor %}

reduce django db calls

I noticed that my django code calls my database very often with the exact same queries.
I understand that a db hit is made when I actually need the data to display on a page or to evaluate. However, my template code looks like this:
template:
{% if item.listing %}
{{ item.name }} text <strong>{{ item.listing|lowestprice }}</strong> more text
{% else %}
{{ item.name }} even more text
{% endif %}
....
{% for listed_item in item.listing %}
....
{% endfor %}
custom filter:
def lowestprice(value):
try:
val = unicode(value[0].price) + unicode(value[0].symbol)
return val
except:
return "not available"
This code hits my db three times. First on template {% if .. %} second on my custom filter, third on the {% for %} loop.
listing is a method of my models class which is returning a raw SQL queryset with some very expensive joins.
def listing(self):
return Universe.objects.raw("ONE HELL OF A QUERY")
How can I reduce my code to hit the db only once?
Edit: Using with works, but is it possible to avoid db hits on custom filters?
You should use with to do the expensive query once and store it the context.
{% with item.listing as item_listing %}
{% if item_listing %} ... {% endif %} ... etc ...
{% endwith %}

Django getting properties of model dynamically

I have a model like
class Document(models.Model):
comment = models.TextField(null=True,blank=True)
upload_date = models.DateTimeField(blank=False)
Document objects are listed in a template as
{% for doc in doc_list %}
{{ doc.comment }}
{{ doc.upload_date }}
{% endfor %}
However, I'd like to reach the properties of doc dynamically like
{{ doc."comment" }}
or
{{ doc|getField:"comment" }}
How can I do that?
Thanks
I assume you mean you want to access fields on a model by using another variable, which you don't necessarily know at the time. So you might have some_var be passed into the template, and this is the field in the model that you'd like to display, such as comment or upload_date.
You could build a template tag to do this:
#register.simple_tag
def get_model_attr(instance, key):
return getattr(instance, key)
Now in your template you can do stuff like:
{% for doc in doc_list %}
{% get_model_attr doc "comment" %}
{% get_model_attr doc some_var %}
{% endfor %}

Django templates: loop through and print all available properties of an object?

I have a database object called manor_stats, with around 30 fields. For most rows, most of these fields will be null.
In my template, I'd like to loop through all the fields in the row, and print info for only the fields that aren't null.
For example, there's a field called "name": I'd like to print <li>Name: {{ manor_stats.name }}</li> in the template ONLY for those objects where the field isn't null. Ideally I'd like to pull in "Name: " from somewhere automatically too, rather than specifying it.
I know I could use {% if manor_stats.name %} to check whether each field is null, but I don't want to do that 30 times for all the fields.
Here's what I have in views.py:
manor_stats = Manors.objects.get(idx=id)
return render_to_response('place.html', { 'place' : place, 'manor_stats' : manor_stats }, context_instance = RequestContext(request))
And then in place.html, I'd like to have something that works approximately like this (pseudocode, with ??? indicating the bits that I don't know how to do):
{% if manor_stats %}
<ul>
{% for manor_stats.property??? in manor_stats %}
{% if manor_stats.property %}
<li>{{ manor_stats.property.field_name??? }} {{ manor_stats.property.value??? }}</li>
{% endif %}
{% endfor %
{% endif %}
Hope that makes sense...
You could add a method to your Manors model that will return all the field values, from there you can just loop over these values in your template checking to see if the value isn't null.
-- models.py
class Manors(models.Model)
#field declarations
def get_fields(self):
return [(field.name, field.value_to_string(self)) for field in Manors._meta.fields]
-- manor_detail.html
{% for name, value in manor_stats.get_fields %}
{% if value %}
{{ name }} => {{ value }}
{% endif %}
{% endfor %}
The following approach only requires defining a single custom template filter (see the docs) - it's DRY'er than having to write or copy a method into every model you need this functionality for.
-- my_app/templatetags/my_tags.py
from django import template
register = template.Library()
#register.filter
def get_fields(obj):
return [(field.name, field.value_to_string(obj)) for field in obj._meta.fields]
You'll need to restart your server to get the new tags registered and available in your templates.
-- my_app/templates/my_app/my_template.html
{% load my_tags %}
<ul>
{% for key, val in object|get_fields %}
<li>{{ key }}: {{ val }}</li>
{% endfor %}
</ul>
Tested in Django 1.11.
NB: Since ._meta is a private attribute it's functionality might well change in the future.
Thanks to the other answers on this post that took me most of the way, particularly W. Perrin.
Use Model._meta.get_fields() in python code.
>>> from django.contrib.auth.models import User
>>> User._meta.get_fields()
(<ManyToOneRel: admin.logentry>,
<django.db.models.fields.AutoField: id>,
<django.db.models.fields.CharField: password>,
<django.db.models.fields.DateTimeField: last_login>,
<django.db.models.fields.BooleanField: is_superuser>,
....
In template, we can define a filter to retrieve all the fields.
├─my_app
│ │
│ ├─templatetags
│ │ │ my_filters.py
│ │
from django import template
register = template.Library()
#register.filter
def get_fields(obj):
return obj._meta.get_fields()
{% for k,v in obj|get_fields %}
<td> {{k}} </td>
{% endfor %}
See this link: https://docs.djangoproject.com/en/2.0/ref/models/meta/#retrieving-all-field-instances-of-a-model