I want to access the elements of a list using Jinja.
Here in the below code both "id" and images are list.
image_name is the field that stores the image
{% for blog in id%}
<h3>{{blog.news_title}}</h3><br/>
<img src="images[loop.index0].image_name"/><br/>
<time>{{blog.news_date}}</time><br/>
click here<br/>
{% endfor%}</li>
Views.py
def BlogViews(request,blog_type):
"""
The blogs are displayed according to the latest, current-month and last-month classification
"""
blog_type=blog_type.replace('-','_')
response_blog=requests.get("API" % (settings.BASE_URL,blog_type),headers=headers,verify=False)
if(response_blog.status_code==200):
data_blog=response_blog.json()
if(data_blog['ErrorCode']==0 and data_blog['SubErrorCode']==0):
blog=BlogYearViews()
blog_images=BlogImages(request,data_blog)
return render(request,"CombinedBlog.html",{"id":data_blog['Data'],"years":blog,"images":blog_images})
else:
return render(request,"Page404.html")
def BlogImages(request,data_blog):
"""
Returns a list of all the images
"""
data_image_list=[]
for i in range(0,len(data_blog['Data'])):
images=data_blog['Data'][i]['image_id']
response_image=requests.get("API"%(settings.BASE_URL),headers=headers,verify=False)
data_image=(response_image.json())
data_image_list=data_image_list+data_image['Data']
return (data_image_list)
You need to zip the two lists together in your view and iterate through them in the template.
blog_images = BlogImages(request, data_blog)
blogs_and_images = zip(data_blog['Data'], blog_images)
return render(request, "CombinedBlog.html", {"blogs_and_images": blogs_and_images, "years":blog})
...
{% for blog, image in blogs_and_images %}
<h3>{{ blog.news_title }}</h3><br/>
<img src="{{ image.image_name }}"/><br/>
<time>{{ blog.news_date }}</time><br/>
click here<br/>
{% endfor %}</li>
Note, you really should be using the {% url %} tag to create the hrefs rather than building it manually like that. Also note, your BlogImages function doesn't need to take the request, since it never uses it, and is anyway extremely un-Pythonic. It should look like this:
def blog_images(data_blog):
data_image_list = []
for blog in data_blog['Data']:
image_id = blog['image_id']
response_image = requests.get("API" % settings.BASE_URL, headers=headers, verify=False)
data_image = response_image.json()
data_image_list.append(data_image['Data'])
return
data_image_list
To access images list using index you can use forloop.counter.
You can use either:
{{ forloop.counter }} # index starts at 1
{{ forloop.counter0 }} # index starts at 0.
In template, you can do:
<img src="{{images[forloop.counter0].image_name.url}}"/>
Advice:
You should consider renaming blog lists as blogs or blog_list inplace of id.
Related
I have a database with blog style documents, i.e., author's name, publication date, body text, etc.
I have built a django framework to output entries from the database as a result of a search term. That part is ok. The problem is that I want to show sections of the body text with the matched search terms highlighted (equivalent to a google search result). This means that I can't create a template tag with the body_text attribute only, because that text is not highlighted. I already did a function that receives as input the query and the body text and outputs the same text with the found search terms in bold.
My problem now is how do I pass this result to the html template?
Using the tutorial from Django documentation suppose you have the following views.py:
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
and the correspondent template:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Now suppose you have the function in views.py:
def signal_tokens(text,query_q):
...
return new_text
What should be the best way to replace the {{ question.question_text } with the output from signal_tokens? My solution was to replicate the context variable with a list of dictionaries, where each dictionary is a copy of each entry, except for the 'question_text' key, where I used signal_tokens result:
def index(request):
query_q = 'test'
latest_question_list = Question.objects.order_by('-pub_date')[:5]
new_context = []
for entry in latest_question_list:
temp_d = {}
temp_d['id'] = entry.id
temp_d['question_text'] = signal_tokens(entry.question_text,query_q)
new_context.append(temp_d)
context = {'latest_question_list': new_context}
return render(request, 'polls/index.html', context)
But the problem is that I need to copy all entries. Is there a more elegant way to solve this problem?
This is an ideal use case for a template filter. Move your highlight code to a file in the templatetags directory, register it as a filter, then you can call it from the template:
{{ question.question_text|highlight:query_q }}
Obviously you will need to pass query_q to the template context as well.
I have a class called Features in my models.py. In my html, I am displaying a list on the right that excludes two of these Features, one is the active feature that has been selected, the other is the most recently added since they are the main content of my page. The remaining Features in the list are displayed by date and do show what I am expecting.
Now, I want to single out the first, second and third Features (title only) in THAT list so I can place them in their own separate divs - because each has unique css styling. There are probably numerous ways of doing this, but I can't seem to figure any of them out.
This is a link to my project to give a better idea of what I want (basically trying to get the content in those colored boxes on the right.)
I'm just learning Django (and Python really), so thanks for your patience and help!
HTML
{% for f in past_features %}
{% if f.title != selected_feature.title %}
{% if f.title != latest_feature.title %}
<h1>{{ f.title }}</h1>
{% endif %}
{% endif %}
{% endfor %}
VIEWS
def feature_detail(request, pk):
selected_feature = get_object_or_404(Feature, pk=pk)
latest_feature = Feature.objects.order_by('-id')[0]
past_features = Feature.objects.order_by('-pub_date')
test = Feature.objects.last()
context = {'selected_feature': selected_feature,
'latest_feature': latest_feature,
'past_features': past_features,
'test': test}
return render(request, 'gp/feature_detail.html', context)
MODELS
class Feature(models.Model):
title = models.CharField(db_index=True, max_length=100, default='')
content = models.TextField(default='')
pub_date = models.DateTimeField(db_index=True, default=datetime.now, blank=True)
def __str__(self):
return self.title
def __iter__(self):
return [
self.id,
self.title ]
You can either store the first three Features in separate variables in your context or add checks to your template loop like {% if forloop.first %} or {% if forloop.counter == 2 %}.
If all you want is to not have the
selected_feature
latest_feature
these two records out of the past_features queryset, then you can use exclude on the past_features query and pass the id's of the selected_features and latest_feature objects.
The views.py would look like:
def feature_detail(request, pk):
selected_feature = get_object_or_404(Feature, pk=pk)
latest_feature = Feature.objects.order_by('-id')[0]
# Collect all the id's present in the latest_feature
excluded_ids = [record.pk for record in latest_feature]
excluded_ids.append(selected_feature.pk)
#This would only return the objects excluding the id present in the list
past_features = Feature.objects.order_by('-pub_date').exclude(id__in=excluded_ids)
test = Feature.objects.last()
context = {'selected_feature': selected_feature,
'latest_feature': latest_feature,
'past_features': past_features,
'test': test}
return render(request, 'gp/feature_detail.html', context)
Django provides a rich ORM and well documented, go through the Queryset options for further information.
For access to a specific object in Django templates see following example:
For access to first object you can use {{ students.0 }}
For access to second object you can use {{ students.1 }}
For access to a specific field for example firstname in object 4 you can use {{ students.3.firstname }}
For access to image field in second object you can use {{ students.1.photo.url }}
For access to id in first object you can use {{ students.0.id }}
I've set up django-taggit and it's working fine, all tags are listed under tags in admin and I can add tags through the admin and in a form.
I'm having real trouble listing the tags in a template (basically I want a long list of all objects with title, url and tags.
Currently I have a method called return tags attached to the model which should return a list of tags for me to iterate over in the template. Well... that is theory...
Model.py
class DefaultResource(models.Model):
#
# This class is the parent class for all resources in the media manager
#
title = models.CharField(max_length=100)
created_date = models.DateTimeField(auto_now_add=True, auto_now=False)
edited_date = models.DateTimeField(auto_now_add=False,auto_now=True)
level = models.ManyToManyField(AssoeLevel)
agebracket= models.ManyToManyField(AgeBracket)
pathway= models.ManyToManyField(AssoePathway)
tags = TaggableManager()
slug = models.SlugField(max_length=100,editable=False,blank=True)
updownvotes = RatingField(can_change_vote=True)
views = models.DecimalField(max_digits=20,decimal_places=2,default=0,blank=True)
score = models.DecimalField(max_digits=20,decimal_places=4,default=0,blank=True)
icon = models.CharField(max_length=254,editable=False,blank=True)
def return_tags(self):
taglist = self.tags.names()
return taglist
view.py
def index(request):
context = RequestContext(request)
default_resource_list = DefaultResource.objects.order_by('-score')
context_dict = {'default_resource_list':default_resource_list}
return render_to_response('mediamanager/index.html', context_dict, context)
index.html
{% for resource in default_resource_list %}
{% for tag in resource.return_tags %}
{{ tag }}
{% endfor %}
{% endfor %}
Currently this is returning an empty list.
I've also tried putting the following into the template
{% for tag in resource.tags.all %}
{{tag.name}}
{% endfor %}
But this also returns an empty list
I am still trying to figure this out, as I want a list of all tags as links to posts that contain that tag. I've only been able to do this by using django-taggit AND django-taggit-templatetags.
Depending on the version of Django you are running try these:
For earlier versions (before 1.5)
Django-taggit-templatetags
For 1.5 or greater (I'm running 1.10 and this worked great)
Django-taggit-templatetags2
Next I am going to try Django tagging, as the docs are much more complete.
To Jon Clements, I am new to StackOverflow and not sure why my answer was deleted. If you have a better solution to this please advise.
This works on django-taggit 1.3.0:
{% for tag in posts.tags.all %}
{{ tag.name }}
{% endfor %}
I am trying out to build full-text searching by using sphinx search, postgresql & django based on this tutorial: http://pkarl.com/articles/guide-django-full-text-search-sphinx-and-django-sp/.
All setup done for sphinx & postgresql and it works but I got trouble when reach on Sample Django code part.
In django views & urlconf, I only changed the function of *search_results* into search and Story model with my own model. For URLConf, I only changed *search_results* into search just same like on views and nothing changed made on search template.
So when I try to search from my form in Django, I get exception:
TypeError at /search/
list() takes exactly 1 argument (0 given)
I also try to changed based on steyblind's comment by change the urlpattern & view definition like this:
(r'^search/(.*)?', search),
def search(request, query=''):
but still keep get TypeError exception.
Is there any mistake I am doing here? Thanks in advance.
Here's my snippets:
Urls.py
(r'^search/(.*)', search),
Views.py
def search(request, query):
try:
if(query == ''):
query = request.GET['query']
results = Flow.search.query(query)
context = { 'flows': list(results),'query': query, 'search_meta':results._sphinx }
except:
context = { 'flows': list() }
return render_to_response('search.html', context, context_instance=RequestContext(request))
search.html
{% extends "base.html" %}
{% block main %}
<div>
<form action="/search/" method="GET">
<input type="text" name="query"/>
<input type="submit">
</form>
{% if flows %}
<p>Your search for “<strong>{{ query }}</strong>” had <strong>{{ search_meta.total_found }}</strong> results.</p>
<p>search_meta object dump: {{ search_meta }}</p>
{% endif %}
<hr/>
{% for s in flows %}
<h3>{{ s.title }}</h3>
<p>(weight: {{ s.sphinx.weight }})</p>
<p>story.sphinx object dump: {{ s.sphinx }}</p>
{% empty %}
<p>YOU HAVEN'T SEARCHED YET.</p>
{% endfor %}
</div>
{% endblock %}
Correct me if I'm wrong, but Django-Sphinx seems to be an abandoned project. The last update to it was a year ago, with most updates being 3-5 years ago. Also, I cannot speak for Django then, but it can do now, out of the box, what you are trying to do with Sphinx.
What version of Django and Python are you using? The error you are getting is strange as list() can take no arguments. Try this in a python shell:
>> list()
[]
Regardless, I've made a few modifications to the code that could possibly help fix the issue. However, if there are no results, you are passing 'flows' as empty in this line:
context = { 'flows': list() }
If you look at the template, this really accomplishes nothing.
urls.py:
(r'^search/', search),
views.py:
def search(request):
query = request.GET.get('query')
if query:
results = Flow.search.query(query)
if results:
context = { 'flows': list(results),'query': query, 'search_meta':results._sphinx }
else:
context = { 'flows': list() }
return render_to_response('search.html', context, context_instance=RequestContext(request))
All that said, I'd highly suggest that since this project is so outdated that you use your own search. Or if you need more functionality, you could use a search app like Haystack which is updated frequently. Using the same urls.py as above, you could implement the below as an easy search that will return all results for a blank search, the actual filtered results for a query.
views.py:
def search(request):
query = request.GET.get('q')
results = Flow.objects.all()
if query:
results = results.query(query)
return render_to_response('search.html', {"flows": results,}, context_instance=RequestContext(request))
I'm trying to do pagination with the page parameter in the URL (instead of the GET parameter). I also want my pagination to be shared code across multiple different templates.
Given that, I think I need to do something like this :
urls.py:
url(r'^alias/page;(?P<page>[0-9]+)/(?P<id>.*)$', alias.get, name="alias"),
tempaltes/alias.html:
<div>...stuff...</div>
{% include "paginator.html" %}
templates/paginator.html :
{% if page_obj.has_previous or page_obj.has_next %}
{% load filters %}
<div class="pagination clear">
{% if page_obj.has_previous %}
‹‹ previous
...
What is somemagic?
Assume I want to keep my url the same except set the page page_obj.previous_page_number
Edit:
You need somemagic to be a variable with the name of the current view.
Try this:
{% with request.path_info|resolve_url_name as current_view %}
{% url current_view page_obj.previous_page_number object.id %}
{% endwith %}
You can get this working with some code from django-snippets:
Variable resolving URL template tag Makes the {% url %} tag resolve variables from context.
Resolve URLs to view name The function resolve_to_name(path) returns the view name for path. You just need to create a filter that uses this function.
This solution wont work with urls like:
'alias/param1_regexp/param2_regexp/page;(?P<page>[0-9]+)/(?P<id>.*)$'
because you've no clue about param1 and param2.
A modification can be done to the django-snippets above to make this kind of urls work:
First snippet modifications:
from django.template import defaulttags, VariableDoesNotExist, Variable
class ResolvingURLNode(defaulttags.URLNode):
def render(self, context):
original_view_name = self.view_name
try:
resolved = Variable(self.view_name).resolve(context)
if len(resolved) > 1:
self.view_name = resolved[0]
if resolved[1]:
self.args = [Variable(arg) for arg in resolved[1]]
elif len(resolved) > 0:
self.view_name = resolved[0]
else:
self.view_name = resolved
except VariableDoesNotExist:
pass
ret = super(defaulttags.URLNode, self).render(context)
# restore view_name in case this node is reused (e.g in a loop) in
# which case the variable might resolve to something else in the next iteration)
self.view_name = original_view_name
return ret
defaulttags.URLNode = ResolvingURLNode
Second snippet modifications
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver
__all__ = ('resolve_to_name',)
def _pattern_resolve_to_name(self, path):
match = self.regex.search(path)
if match:
name = ""
if self.name:
name = self.name
elif hasattr(self, '_callback_str'):
name = self._callback_str
else:
name = "%s.%s" % (self.callback.__module__, self.callback.func_name)
if len(match.groups()) > 0:
groups = match.groups()
else:
groups = None
return name, groups
def _resolver_resolve_to_name(self, path):
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
resolved = pattern.resolve_to_name(new_path)
if resolved:
name, groups = resolved
else:
name = None
except Resolver404, e:
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0 ['tried']])
else:
if name:
return name, groups
tried.append(pattern.regex.pattern)
raise Resolver404, {'tried': tried, 'path': new_path}
# here goes monkeypatching
RegexURLPattern.resolve_to_name = _pattern_resolve_to_name
RegexURLResolver.resolve_to_name = _resolver_resolve_to_name
def resolve_to_name(path, urlconf=None):
return get_resolver(urlconf).resolve_to_name(path)
Basically, resolve_to_name returns the name of the view and it's parameters as a tuple, and the new {% url myvar %} takes this tuple and uses it to reverse the path with the view name and it's parameters.
If you don't like the filter approach it can also be done with a custom middleware.
Previous answer
You should check django-pagination, it's a really nice django application, easy tu use and gets the job done.
With django pagination the code to paginate an iterable would be:
{% load pagination_tags %}
{% autopaginate myiterable 10 %} <!-- 10 elements per page -->
{% for item in myiterable %}
RENDERING CONTENT
{% endfor %}
{% paginate %} <!-- this renders the links to navigate through the pages -->
myiterable can be anything that is iterable:list, tuple, queryset, etc
The project page at googlecode:
http://code.google.com/p/django-pagination/
It will be something like the following. Except I don't know what you mean by id so I just put a generic object id. The syntax for url is {% url view_name param1 param2 ... %}
{% url alias page_obj.previous_page_number object.id %}
Updated base on your need:
{% url alias page_obj.previous_page_number object.id as prev_url %}
{% include "paginator.html" %}
...
{% if page_obj.has_previous %}
‹‹ previous