How to use __repr__ method within django template? - python

For example, there is an object in a nested loop:
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if field.is_hidden %} {{ field.field }} {% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
Now I want to check the class name and some information about field.field, so I use field.field.__repr__() to replace field.field.
However, the django template complains about it after the change:
Variables and attributes may not begin with underscores: 'field.field.__repr__'
Does anyone have idea about this? And is there any better way to debug for a variable in django template? (I tried {% debug %} but found it awful when I want to check a variable in a nested loop..)

{{ value|stringformat:'r' }}
uses the string % operator style formatting with the r format which uses repr()

You could easily write a template filter which allows you to do {{ var|asrepr }}. See the documentation, but it'll look something like this:
#register.filter
def asrepr(value):
return repr(value)

Related

Django iterate queryset just n number of times in templates

My issue is quite simple. I am using Django taggit.
I want to iterate this only 2 times. Means to display only 4 tags in templates.
{% for tag in data.tags.all %}
{{tag}}
{% endfor %}
I have tried this, but it is not making any sense:
{% for tag in data.tags.all|ljust:"2" %}
{{tag}}
{% endfor %}
Can anyone suggest how can I achieve it?
You can make use of the |slice template filter [Django-doc]:
{% for tag in data.tags.all|slice:':2' %}
{{ tag }}
{% endfor %}

How do minus in django template [duplicate]

It is able to write {{ myval.add:5 }}, {{ myval|add:value }} and even {{ myval|add:-5 }}.
However, I can't find out what I should type to add value * -1 like {{ myval|add:-value }}. This doesn't work, sadly.
You need to use double quotes:
{{ myval|add:"-5" }}
This subtracts five from myval.
The built-in Django template tags/filters aren't all-encompassing, but it's super easy to write your own custom template tags: https://docs.djangoproject.com/en/dev/howto/custom-template-tags/
You could make your own subtract template tag pretty easily:
#register.filter
def subtract(value, arg):
return value - arg
Use django-mathfilters from PyPI: https://pypi.python.org/pypi/django-mathfilters
To install :
$ pip install django-mathfilters
Then add mathfilters in your INSTALLED_APPS.
In template:
{% load mathfilters %}
<ul>
<li>8 + 3 = {{ 8|add:3 }}</li>
<li>13 - 17 = {{ 13|sub:17 }}</li>
{% with answer=42 %}
<li>42 * 0.5 = {{ answer|mul:0.5 }}</li>
{% endwith %}
{% with numerator=12 denominator=3 %}
<li>12 / 3 = {{ numerator|div:denominator }}</li>
{% endwith %}
<li>|-13| = {{ -13|abs }}</li>
</ul>
I recently started working with Django and stumbled upon this one as well: I needed a very simple template loop that stops printing after n times and shows a "more" link to toggle the rest of the items.
With great interest I read the struggle of people trying to understand why this is not being added to the Django default filters (since before 2013). I didn't feel like creating a custom template tag and I kind of found a way to subtract 2 variables using strings and add in combination with with and stringformat
Let's say I have a list of items where I want to print the first 2 and hide the rest, showing how many hidden items are there, eg.
John, Anna and 5 others like this (when given a list of 7 items)
As long as the number of visible items is harcoded in the template (eg. 2), it's possible to add the negative 2 |add:"-2", but I wanted the number of visible items to be a variable as well. The Math-filter library as suggested above doesn't seem up to date (I haven't tested it with Django 2.x).
The trick seems to be to use the add helper to concat the strings "-" with the integer as string, so it can be coerced back to a negative integer in a any consecutive calls to the add helper. This doesn't work however if the value is not a string, so that's where the stringformat helper comes in.
With string value
template posts.html (note how visible is explicitely passed as string - alternative below)
{% for post in posts %}
<h4>{{ post.title }}</h4>
...
{% include 'show_likes.html' with likes=post.likes visible="3" %}
{% endfor %}
template show_likes.html (note the add:0 to make the boolean operator work)
{% with show=visible|default:"2" %}
{% for like in likes %}
{% if forloop.counter <= show|add:0 %}
{% if not forloop.first %},{% endif %}
{{ like.username }}
{% endif %}
{% endfor %}
{% if likes|length > show|add:0 %}
{% with rest="-"|add:show %}
and {{ likes|length|add:rest }} more
{% endwith %}
{% endif %}
like this
{% endwith %}
Alternative with integer
You could just convert your integer to a string in the calling template using |stringformat:"d"
If however the number of visible items you want to show is an integer, you'll have to add a call to stringformat:"d" to have it converted to string
template posts.html
{% for post in posts %}
<h4>{{ post.title }}</h4>
...
{% include 'show_likes.html' with likes=post.likes visible=3 %}
{% endfor %}
template show_likes.html
{% with show=visible|default:2 %}
{% with show_str=show|stringformat:"d" %}
{% for like in likes %}
{% if forloop.counter <= show %}
{% if not forloop.first %},{% endif %}
{{ like.username }}
{% endif %}
{% endfor %}
{% if likes|length > show|add:0 %}
{% with rest="-"|add:show_str %}
and {{ likes|length|add:rest }} more
{% endwith %}
{% endif %}
{% endwith %}
{% endwith %}
Since I'm a very beginner with Django and Python, I'm pretty sure this approach is far worse than actually creating a custom helper! So I'm not suggesting anyone should be using this. This was just my attempt on trying to solve this with the available template helpers and without any custom stuff.
Hope this helps
Lo primero es multiplicar por -1 para convertirlo en una valor negativo y guardarlo en una variable y posterior a usar la suma
The first thing is to multiply by -1 to turn it into a negative value
and save it in a variable and then use the add
{% widthratio val2 1 -1 as result %}
{{result|add:val1}}
After search I found that I can make {% with var=value %} with filters to make the arithmetic operations "with other variables or not"
For example: I have x = 5 and y = 3 and need to add the y's value to x value, all what I need is these steps:
1- Create variable x : {% with x=5 %}
2- Create variable y : {% with y=3 %}
3- In my HTML tags, say <h1>, write that : <h1>{{ x|add:y }}</h1>
4- Close the y's with : {% endwith %}
5- Close the x's with : {% endwith %}
Hope it works with you, it worked with me.
{% with i=3 %}
{% with x=1 %}
<h1>{{i|add:x}}</h1> <!-- result is 4 -->
{% endwith %}
{% endwith %}

django concat string with comma in template

I am newbie in django. How can I concat string in a for loop in django template
{% for lead in project.leaders %}
{% if forloop.counter == 1 %}
{% lead_member = lead.0 %}
{% else %}
{% lead_member = ','.lead.0 %}
{% endif %}
{{ lead_member }}
{% endfor %}
Finally my lead_member should be test1,test2,test3....
what is happening now (my current code)
{% for lead in project.leaders %}
{{ lead.0}}
{% endfor %}
and the output is test1test2test3.... but i want to make same as test1,test2,test3....
Try this. it works
{% for lead in project.leaders %}
{{ lead.0 }}{% if not forloop.last %}, {% endif %}
{% endfor %}
There's no need to assign anything, nor do you need that type of complexity by using assignment tags. To keep your templating stupid-simple, you could always do this in your view, or even at the model level:
# don't step on the `join` built-in
from django.template.defaultfilters import join as join_filter
class Project(models.Model):
#property
def leaders(self):
return join_filter(self.objects.values_list('some_field', flat=True), ', ')
Then all you have to do in the template is:
{{ project.leaders }}
It's hard to understand your question, but I hope i did it. There is a number of related questions such as String-concatination,
How to concatenate in django
It's possible to create first string, concatinate it with comma and new string for every iteration. You are also able to make smth like ','.join(list_of_strings) on your server side before rendering. You can also join your list in templating by {{ list|join:", " }}.

Django related_name

I'm trying to do something like:
{% for property in current_listing %}
{% for property_image in property.property_images.all %}
{% endfor %}
{% endfor %}
But I would like something like:
{% for property in current_listing %}
{% for property_image in property.property_images.**ORDER_BY('-order')[0]** %}
{% endfor %}
{% endfor %}
How can I do this?
If I understand what you want, you can try custom template filter:
from django import template
register = template.Library()
#register.filter
def get_first_ordered_by(queryset, order):
return queryset.order_by(order)[0]
Then on a template:
{% load my_tags %}
{% with image=property.property_images.all|get_first_ordered_by:'-order' %}
{{ image }}
{% endwith %}
Note, that you can not use {% for %} since result of get_first_ordered_by is not iterable.
You can add a method to you Model's class definition that returns the query you want, then cann that method from you template.

How can I concatenate forloop.counter to a string in my django template

I am already trying to concatenate like this:
{% for choice in choice_dict %}
{% if choice =='2' %}
{% with "mod"|add:forloop.counter|add:".html" as template %}
{% include template %}
{% endwith %}
{% endif %}
{% endfor %}
but for some reason I am only getting "mod.html" and not the forloop.counter number. Does anyone have any idea what is going on and what I can do to fix this issue? Thanks alot!
Your problem is that the forloop.counter is an integer and you are using the add template filter which will behave properly if you pass it all strings or all integers, but not a mix.
One way to work around this is:
{% for x in some_list %}
{% with y=forloop.counter|stringformat:"s" %}
{% with template="mod"|add:y|add:".html" %}
<p>{{ template }}</p>
{% endwith %}
{% endwith %}
{% endfor %}
which results in:
<p>mod1.html</p>
<p>mod2.html</p>
<p>mod3.html</p>
<p>mod4.html</p>
<p>mod5.html</p>
<p>mod6.html</p>
...
The second with tag is required because stringformat tag is implemented with an automatically prepended %. To get around this you can create a custom filter. I use something similar to this:
http://djangosnippets.org/snippets/393/
save the snipped as some_app/templatetags/some_name.py
from django import template
register = template.Library()
def format(value, arg):
"""
Alters default filter "stringformat" to not add the % at the front,
so the variable can be placed anywhere in the string.
"""
try:
if value:
return (unicode(arg)) % value
else:
return u''
except (ValueError, TypeError):
return u''
register.filter('format', format)
in template:
{% load some_name.py %}
{% for x in some_list %}
{% with template=forloop.counter|format:"mod%s.html" %}
<p>{{ template }}</p>
{% endwith %}
{% endfor %}
You probably don't want to do this in your templates, this seems more like a views job: (use of if within a for loop).
chosen_templates=[]
for choice in choice_dict:
if choice =='2':
{% with "mod"|add:forloop.counter|add:".html" as template %}
template_name = "mod%i.html" %index
chosen_templates.append(template_name)
Then pass chosen_templates to your template where you will have only
{% for template in chosen_templates %}
{% load template %}
{% endfor %}
Also, I don't quite understand why you are using a dict to select the template with a number that is not in the dictionnary. for key,value in dict.items() may be what you are looking for.
Try without using the block "with"
{% for choice in choice_dict %}
{% if choice =='2' %}
{% include "mod"|add:forloop.counter|add:".html" %}
{% endif %}
{% endfor %}

Categories

Resources