Problems passing a dictionary to a template in Django - django

I am having trouble with what seems to be a simple problem:
I want to pass a dictionary to a template, and then have the template render that dictionary on the page. However, when I run the page, the dictionary doesn't show up...
Here's my views page:
def display_meta(request):
values = request.META.items()
values.sort()
c = Context(values)
return render_to_response('meta_data.html', c)
And here's my template:
{% extends "base.html" %}
{% block content %}
<table>
{% for k, v in c %}
<tr><td> {{k}} </td><td> {{v}} </td></tr>
{% endfor %}
</table>
{% endblock %}
I am not sure what is going wrong. Any help would be greatly appreciated. Thanks!

You need to pass context as a dict. You would do so like
def display_meta(request):
values = request.META.items()
values.sort()
return render_to_response('meta_data.html', {'c': values})
Each key represents the variable that will be available, in this case c will be a dict with the items in values

Related

How to pass arguments to a function in for loop Jinja DJANGo

How can I pass an argument to a function in for loop?
I use Django and jinja and I want to somehow pass an argument to my function but I don't know whether it is possible, didn't find any pieces of information online
{% for student in get_students%}
<tr>
<td>User.name</td>
{% for colum in get_columns %}
{% for grade in colum.get_grade_by_user(student.id) %} <=== like that
<td>{{grade.value}}</td>
{% endfor %}
{% endfor %}
</tr>
{% endfor %}
def get_grade_by_user(self, student):
get_grade = Grade.objects.all().filter(date=self.id, user=student)
return get_grade
You can extend the global namespace by adding a reference to your functions before loading the templates:
from jinja2 import Environment, FileSystemLoader
def my_funct(a, b):
return a + b
env = Environment(loader=FileSystemLoader('/path/to/templates'))
env.globals['my_funct'] = my_funct

Iterate through model fields in jinja template

I have several models in my application, and as I will have some views doing the same thing (form + tables showing existing records in my model), but implemented dfferently because of the model, which will be different in each case, I was wondering if it was possible to make it generic.
I googled a bit and was not able to find anything relevant to my case.
What I would like to achieve:
In my view, I want to go through each object from the model that I passed to the template, for example:
return render_template('addstatus.html', form=form, statuses=Status.query.all(),
target_model="Status", fields=Status.__mapper__.c.keys())
But I want to have only one view, whatever the model will be, so I am not able to know in advance the fields of my model, the number of columns and so on.
I want to have something like that in my view:
{% for obj in objects %}
{% for field in obj.fields %} (not existing)
<h1> {{ field }} :: {{ obj.fields.field.value }}
{% endfor %}
{% endfor %}
Is it something possible? How can I achieve that?
You can add this method to your db.Model class (either by subclassing or by monkeypatching):
from sqlalchemy.orm import class_mapper, ColumnProperty
def columns(self):
"""Return the actual columns of a SQLAlchemy-mapped object"""
return [prop.key for prop in class_mapper(self.__class__).iterate_properties
if isinstance(prop, ColumnProperty)]
Then you can use {% for col in obj.columns() %} to iterate over the column names.
I had a similar issue, and wanted something purely Jinja2 based. This will return all of the keys/fields in your "obj" table, and worked well for me:
obj.__table__.columns._data.keys()
Here it is implemented in your sample code
{% for obj in objects %}
{% for field in obj.__table__.columns._data.keys() %}
<h1> {{ field }} :: {{ obj[field] }} </h1>
{% endfor %}
{% endfor %}

Django template if statement always evaluates to true

This seems like it should be pretty straightforward, but for some reason I am unable to solve this problem. I'm using Django 1.4. I am trying to do a basic check to see if a list QuerySet is empty or not during template rendering, but the if statement I'm using seems always to evaluate to true.
I have a Django template that reads:
{% extends 'includes/base.html' %}
{% if object_list %}
...
{% block data %}
{% for object in object_list %}
...
{{ object.create_date }}
...
{% endfor %}
{% endblock data %}
...
{% endif %}
'base.html' has the block:
<body>
{% block content %}
...
<div class="row-fluid">
<div class="span12">
{% block data %}
<div align="center"><i>No data.</i></div>
{% endblock data %}
</div><!-- span12 -->
</div><!-- row -->
{% endblock content %}
...
</body>
The view function generating the QuerySet is here:
def barcode_track(request, model):
query = request.GET.get('barcode_search', '')
object_list = model.objects.all()
if query:
object_list = model.objects.filter(barcode__icontains=query)
return render_to_response('barcode_track/barcode_list.html',
{'object_list': object_list, 'query': query},
context_instance=RequestContext(request))
Which is called via this form:
<form id="barcode_search_form" method="get" action="" class="form">
<input type="text" name="barcode_search" value="{{ query }}" />
<button type="submit" class="btn">Search</button>
</form>
And the urls.py line:
urlpatterns = patterns('barcode_track.views',
url(r'^$', 'barcode_track', {'model': Barcode},
name="barcode_track"),)
The idea is that results will only be presented if they exist in object_list, and otherwise the parent block will remain unaltered. I have tried changing the name of object_list, and I have printed {{ dicts }} to the page to ensure that object_list is, in fact, empty (which it is). I am not using a generic view, although I realize that the name suggests as much. I have actually had this trouble in a different app I wrote using similar logic, so I must be doing something systematically incorrectly.
What am I missing here?
You can't wrap control flow tags like if around a block. Your problem is that the child template's definition for block data is being used simply because it's there.
You can fix it by placing the if tag inside block data. If you want to inherit the parent's contents when the list is empty, add an else case that expands to {{ block.super }}.

Accessing initial value of django forms when iterating over the fields

I'm trying to do something pretty simple; I'd like to apply a "hidden" style to a form field inside a django template when I've passed in some initial value like this:
form = form_class(initial={'field':data})
Normally, it would be like this:
<li class="{{form.somefield.name}} {% if form.somefield.initial %} hidden{% endif %}>
...
</li>
But I'm iterating over the forms, so what I want do do is something that looks like this:
{% for field in form %}
<li class="{{field.name}} {% if field.initial %} hidden{% endif %}">
...
</li>
{% endfor %}
but this doesn't work, because field.initial only has the value defined as initial to the field in the form, not the data that's passed in at the form's creation. Is there a good solution for this besides just breaking out the iterating into individual forms?
Some (bad) solutions I've thought of:
overriding init to stuff values form self.initial into self.fields;
writing a template tags called {% hideifhasinitial %}
adding a method to the form that uses zip on self and self.initial (doesn't work, since self.initial only had one element and self had 4, it only iterated over 1 element, and the keys (field names) didn't match up).
how about this?
{% for field in form %}
{% if field.name in field.form.initial.keys %}
...
{% endif %}
{% endfor %}
Initial data can be accessed on the value attribute, initial data represents the value of the field:
{{field.value}}
Turns out there's a way easier way to do this.
{% if field.name in form.initial.keys %}
The solution with the initial keys has not worked for me, because the field contains as a value an empty string. I had to write my own custom tag:
from django import template
register = template.Library()
#register.simple_tag
def field_empty(field):
if not field.form.initial.get(field.name):
return ' hidden'
return ''
In your example, I would use the tag this way:
<li class="{{ field.name }} {% field_empty field %}">

Use variable as dictionary key in Django template

I'd like to use a variable as an key in a dictionary in a Django template. I can't for the life of me figure out how to do it. If I have a product with a name or ID field, and ratings dictionary with indices of the product IDs, I'd like to be able to say:
{% for product in product_list %}
<h1>{{ ratings.product.id }}</h1>
{% endfor %}
In python this would be accomplished with a simple
ratings[product.id]
But I can't make it work in the templates. I've tried using with... no dice. Ideas?
Create a template tag like this (in yourproject/templatetags):
#register.filter
def keyvalue(dict, key):
return dict[key]
Usage:
{{dictionary|keyvalue:key_variable}}
You need to prepare your data beforehand, in this case you should pass list of two-tuples to your template:
{% for product, rating in product_list %}
<h1>{{ product.name }}</h1><p>{{ rating }}</p>
{% endfor %}
Building on eviltnan's answer, his filter will raise an exception if key isn't a key of dict.
Filters should never raise exceptions, but should fail gracefully. This is a more robust/complete answer:
#register.filter
def keyvalue(dict, key):
try:
return dict[key]
except KeyError:
return ''
Basically, this would do the same as dict.get(key, '') in Python code, and could also be written that way if you don't want to include the try/except block, although it is more explicit.
There is a very dirty solution:
<div>We need d[{{ k }}]</div>
<div>So here it is:
{% for key, value in d.items %}
{% if k == key %}
{{ value }}
{% endif %}
{% endfor %}
</div>