I have a list with IP Addresses. I also have a nested dictionary which uses those addresses as keys. For example:
my_list = ['1.2.3.4', '8.8.8.8']
my_dic = {'data': {'1.2.3.4': 'My First Data', '8.8.8.8': 'My Second Data'}}
In my template I am trying to this:
for each in my_list:
print(my_dic['data'][each])
Everything works well until I hit that each key. So if I just print my_dic or my_dic[data] it will all work correctly. But when I add the each index nothing shows up in the webpage
I have printed each independently so I know that it works correctly.
This also works as expected when I run the loop in my IDE so I know the logic is right.
In django my code looks like this:
{% if my_dic.data %}
{% for each in my_list %}
<p>{{ my_dic.data.each }}</p>
{% endfor %}
{% endif %}
I'm new to Django so not sure if I'm overlooking something silly. Anyone know what I am missing here?
EDIT
Found a duplicate HERE which covers my issue. Same issue Vishnu Ks pointed out.
The issue is that when you try to access data.each Django will look for data["each"] and not data[each].Since there is no key named "each" in my_dic nothing would be printed.
If you want to access the value of data[each] inside the template you need to write a custom template filter.
from django.template.defaulttags import register
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
Then change the Django template code to this.
{% if my_dic.data %}
{% for each in my_list %}
<p>{{ my_dic.data|get_item:each }}</p>
{% endfor %}
{% endif %}
See Django template how to look up a dictionary value with a variable for more details.
Related
i am kind of new to django and i ran into a problem i couldnt find a solution to. In a template i render data from a custom context processor. There i use a for loop over all the queried items and a if statement, that checks that the data belongs to the person that is currently logged in:
{% for item in all_soli_accs %}
{% if item.owner == request.user.get_username %}
<a href="{% url 'url-soli-acc' item.soli_acc %} ">
{{ item.soli_acc }}
</a>
{% endif %}
{% endfor %}
Weirdly, the if statement doesnt return "true", when it is supposed to. The rendering doesnt output anything. In order to debug it, i tried to render {{item.owner}} and {{request.user.get_username}} and check if there are errors. But rendered as a variable, they return the same output, which lets me assume that it is all fine. I am confused. Does anyone has a solution to that? Do you need further information?
best regards
Use
request.user.username
Instead of
request.user.get_username
Doing this works
{% for comment in comments %}
{{ comment.user }}
{% endfor %}
However, I want to get all the comment.user values in the dictionary without using a for loop. Is this possible?
I ask because I need to do this check
{% if name in comment.user %} # check if name is in any one of the comments
# do something
{% endif %}
Basically, you need to get all the distinct users from comments. You have to do it in the view and pass users queryset back into the template:
users = User.objects.filter(comment__in=comments).distinct()
I've been pulling my hair out over this and can't figure out what's going on.
In my view I can do this:
from django.contrib.comments import Comment
...
context['comments'] = Comment.objects.filter(object_pk = self.kwargs['pk'])
...
Then in my template when I do:
{% for comment in comments %}
{{ comment.comment }}
{% endfor %}
It works perfectly and displays each comment...
However when I try to use the django template tags for comments I get an empty list
{% load comments %}
{% get_comment_list for video as comments %}
{% for comment in comments %}
{{ comment.comment }}
{% endfor %}
{{ comment_list|length }} // displays '0'
video in the above code is the object instance in the template context - I use it elsewhere in the template and it works fine - ie {{ video.title }}, {{ video.id }}
Also - other comment template tags seem to work fine:
{% render_comment_list video %}
displays the test template I have located at comments/list.html - this template just prints out "hello world".
Any idea what's going on here or how to debug it?
Just a guess but, when you do this:
Comment.objects.filter(object_pk = self.kwargs['pk'])
in the view, you aren't specifying a content_type (Video) for the comments you wish to get, so you are retrieving all comments for any object with the id 'pk' - maybe that's why you are seeing comments when you do it manually, but none when you leave it up to the template tag. Maybe the comments aren't attached to the correct ContentType - you could check this in the django admin
Let's make this very easy for my fellow SOians(?).
This is how normally the custom template tags work -
Template ->
{% block content %}
blah blah blah
{% custom_tag_load %}
{% endblock %}
The custom_tag_load is called and it returns a string. What I want to return is a queryset which I could possibly use like this ->
{% block content %}
blah blah blah
{% for x in custom_tag_load %}
{{ x.datetime }}
{% endfor %}
{% endblock %}
Note -> What I'm basically trying to do is to avoid passing the queryset through the view, and I'm not sure if I should be comfortable storing querysets in my global context.
You can return anything you like from a tag, including a queryset. However, you can't use a tag inside the for tag - you can only use a variable there (or a variable passed through a filter). What you could do is get your tag to put the queryset into a variable in the context, and use that variable in the for loop. See the docs on how to set a variable from a tag - although note that the development version has an easier method for doing this.
However, you shouldn't be concerned about putting a queryset into a context processor, either. Don't forget that querysets are lazy, so no database hit will be made unless the queryset is evaluated or iterated in the template.
A template tag can do whatever you want. From your pseudo code, you could accomplish what you need with an inclusion tag:
#my_tags.py
from django import template
from my_app.models import MyModel
register = template.Library()
#register.inclusion_tag('my_template.html')
def my_custom_tag():
things = MyModel.objects.all()
return {'things' : things}
#my_template.html
{% if things %}
<ul>
{% for thing in things %}
<li>{{ thing }}</li>
{% empty %}
<li>Sorry, no things yet.</li>
{% endfor %}
</ul>
{% endif %}
#the_view.html
{% load my_tags %}
{% my_custom_tag %}
Alternatively, you could write a custom tag that adds a queryset to the context. Hope that helps you out.
I had these same problems recently and most of the answers here were kind of outdated, but a little digging through Django's documentation and I was able to sort it out.
Like most of the answers above, you can return basically anything using a template tag, but it all depends on how you register the template tags. So say you want to use a template tag to return a queryset to be available for any template you wish, you could register the template tag as a simple tag just like this
from django import template
from blog.models import Post
from django.template.defaulttags import register
register = template.Library()
#register.simple_tag
def get_posts():
return Post.objects.all()
Then to be able to access this in your template, you first need to load this file in your template like
{% load templatetagfile %}
And then to loop through, you need to first assign it to a variable before looping through
{% get_posts as posts %}
{% for post in posts %}
{{ post.whatever }}
{% endfor %}
The first line there makes the queryset from the get_posts function available as a variable named posts which you can then loop through.
I'm trying to build a blog app and the problem is when I use tag 'truncatewords_html' in my template to truncate posts longer than specified number of words, I need to link to complete post by some title like 'read more...' after truncation. So I should know that the post was truncated or not.
P.S.: Is this a pythonic way to solve the problem?
{% ifequal post.body|length post.body|truncatewords_html:max_words|length %}
{{ post.body|safe }}
{% else %}
{{ post.body|truncatewords_html:max_words|safe }}read more
{% endifequal %}
This is pretty convoluted but django has some weird corners. Basically I figure if the string length is the same if you truncate at x and x+1 words then the string has not been truncated...
{% ifnotequal post.body|truncatewords_html:30|length post.body|truncatewords_html:31|length %}
read more...
{% endifnotequal %}
You could write a custom template tag (see django docs), or manually check in the template, whether the content you want to display exceeds the given length via length builtin filter.
It comes down to personal preference, but for my taste you're doing way too much work in the template. I would create a method on the Post model, read_more_needed() perhaps, which returns True or False depending on the length of the text. eg:
def read_more_needed(self):
from django.utils.text import truncate_html_words
return not truncate_html_words(self.body,30)==truncate_html_words(self.body,31)
Then your template would read:
{% if post.read_more_needed %}
{{ post.body|truncatewords_html:30|safe }}read more
{% else %}
{{ post.body|safe }}
{% endif %}
Check out http://code.djangoproject.com/ticket/6799
This patch provides a method to replace the default elipses for truncated text.