How to get a model by modelname in django template - django

I have model LandingSnippet that contains attribute ...model = CharField()..., and it is related to context keyword (for example cars in context below)
I have next code in my view
def GeneratedLanding(request):
snippets = LandingSnippet.objects.all().filter(view_on=True).order_by('order')
context = {
'snippets':snippets,
...
'cars':Car.objects.all(), # this is cars
...
return render(request,'qlanding/generateindex.html',{'context':context})
how i can get querySet cars that is in context by keyword cars as a string
for example
{{context}}
prints
{'snippets': <QuerySet [<LandingSnippet: Snippet1Title>, <LandingSnippet: 2 - about - Лучшая служба развозки детей>]>, 'services': <QuerySet []>, 'cars': <QuerySet []>, 'faqs': <QuerySet []>}
and
{{snippet.model}}
prints
cars
QUESTION:
How can i get the {{ context.cars }} ? I think something like context[snippet.model] where snippet.model='cars'
i want push it inside another template when include
{% if snippet.module %}
{% with "qlanding/snippets/module/"|add:snippet.module|add:".html" as path %}
{% include path with model=context[snippet.model] %} # But this is incorect while rendering
{% endwith %}
{% endif %}

you can write a simple template tag like this:
first in your app directory create a directory named templatetags this directory must contains an empty file named __init__.py
create a file with any name in this directory. for example load_from_context
write these code on this file
from django import template
register = template.Library()
#register.tag(name="GetFromContext")
def get_from_context(parser, token):
bits = token.split_contents()
node_list = parser.parse(('endGetFromContext',))
variable = bits[1]
return GetFromContextNode(node_list, variable)
class GetFromContextNode(template.Node):
def __init__(self, node_list, variable):
self.node_list = node_list
self.variable = variable
def render(self, context):
variable_value = template.Variable(self.variable).resolve(context)
with context.push():
context['model'] = context.get(variable_value)
return self.node_list.render(context)
then in your template you can use it like this
{% load load_from_context %}
{# any code in your template #}
{% GetFromContext snippet.model %}
{% include path %}
{% endGetFromContext %}

#vorujack , I get the same error still. but based on your solution I got next.
from Django import template
register = template.Library()
#register.simple_tag
def get_model_from_context(context,model_name):
return context[model_name]
and how I used in view
{% get_model_from_context context=context model_name=snippet.model as model %}
{% include "qlanding/snippets/module/"|add:snippet.module|add:".html" with model=model %}
many thanks for #vorujack

Related

Django templates {% include %} fallback value

I'm trying to dynamically load a template like so:
{% include 'some-folder/'|add:var|add:'.html' %}
But these templates are not always present. So I would like to add a fallback value/default template to be loaded if one being requested is not found.
Is this possible? If not (out-of-the-box), how can I write a custom templatetag that does so?
from django import template
register = template.Library()
#register.simple_tag
def get_template_path(var1, var2):
template_path = 'some-folder/' + var1 + '/' + var2 + '.html'
default_template = 'some-folder/default_template.html'
try:
template.loader.get_template(template_path)
return template_path
except TemplateDoesNotExist:
return default_template
In template call this template tag like this:
{% load get_template_path %}
{% get_template_path var1='qq' var2='ee' as temlate_path %}
{% include template_path %}

Django: context of modified query list

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.

django creating template filters

views.py
#register.filter(name="avl")
def avl_facilities(obj):
return obj.avl_facilities()
#register.filter
def na_facilities(obj):
return obj.na_facilities()
models.py
class Model(models.Model):
#some code .....
def avl_facilities(self):
item = ['bar','bank','music','wifi','offers','credit']
avl = []
for i in item:
if getattr(self,i) == True:
avl.append(i)
return avl
def na_facilities(self):
item = ['bar','bank','music','wifi','offers','credit']
na = []
for i in item:
if getattr(self,i) == False:
na.append(i)
return na
html
<div class="facility pad10">
{% for item in data.rest|avl %}
/* data.rest is appropriate instance of model defined above*/
<span class="label label-danger mrg2 pad5 pull-left">
{{item|title}}
</span>
{% endfor %}
</div>
errro
Invalid filter: 'avl_facilities'
doubt
i am not able to understand that if the avl_facilities inside the model is returning proper iterable list , but its not working as a template filter , thanks in advance
You can't define filters in views.py. You have to put them in a new file inside a templatetags directory.
You should know though that both of these filters are totally unnecessary. It's quite possible to call model methods from the template, as long as they don't take arguments:
{% for item in data.rest.avl_facilities %}

Django-Template : Get Variables in a Tag block !

I need to retrieve an optional number saved in DB , to a custom template tag i made . which to retrieve , a variable ( a photo ID ) included in this Gallery . within the gallery loop .
{% get_latest_photo {{photo.id}} %}
How to accomplish that ?!
P.s : I know that can be done with inclusion tag , but in the present time how to make it fix this one !
Edit the template html file :
{% for album in albumslist %}
{% get_latest_photo photo.id %}
{% for photo in recent_photos %}
<img src='{% thumbnail photo.image 200x80 crop,upscale %}' alt='{{ photo.title }}' />
{% endfor %}
{{ album.title }}
{% endfor %}
templatetag
from django.template import Library, Node
from akari.main.models import *
from django.db.models import get_model
register = Library()
class LatestPhotoNode(Node):
def __init__(self, num):
self.num = num
def render(self, context):
photo = Photo.objects.filter(akar=self.num)[:1]
context['recent_photos'] = photo
return ''
def get_latest_photo(parser, token):
bits = token.contents.split()
return LatestPhotoNode(bits[1])
get_latest_photo = register.tag(get_latest_photo)
P.s Its working very well when i replace album.id (in {% get_latest_photo photo.id %} ) with a number which acts as an album id and retrieve the photo from .
Regards
H. M.
You don't put the brackets around variables when you use them in template tags.
{% get_latest_photo photo.id %}
To evaluate correctly the num variable I think you should modify your LatestPhotoNode class like this:
class LatestPhotoNode(Node):
def __init__(self, num):
self.num = template.Variable(num)
def render(self, context):
num = self.variable.resolve(self.num)
photo = Photo.objects.filter(akar=num)[:1]
context['recent_photos'] = photo
return ''
Are you sure your template tag is written properly? For example, you need to use Variable.resolve to properly get the values of variables: Passing Template Variables to the Tag
I had the same problem problem and after reading the docs, I solved it using this
class LatestPhotoNode(Node):
def __init__(self, num):
self.num = template.Variable(num)
def render(self, context):
num = self.num.resolve(context)
photo = Photo.objects.filter(akar=num)[:1]
context['recent_photos'] = photo
return ''
If you are trying to render multiple variables, using json.dumps is very useful.

Django: How can you get the current URL tagname (for pagination)?

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