I am using Django's Template Fragment Caching so in a template.html file
{% extends 'base.html' %}
{% load cache %}
{% block content %}
{% cache 500 "myCacheKey" %}
My html here...
{% endcache %}
{% endblock %}
This is working fine - I can see it's getting cached and hit but the view is doing something expensive to provide data to this view and thats getting called every time.
In views.py
def index(request)
data = api.getSomeExpensiveData()
return render_to_response('template.html', {'data':data} )
So how do I tell if the cache is avail before the call to api.getSomeExpensiveData()?
I can't use cache.get('myCacheKey') as the cache isn't found - does it use some naming scheme and if so can I either use something like
cache.get(cache.getTemplateFragmentKey("myCacheKey"))
or
cache.getTemplateFragment("myCacheKey")
If you do not use that data in your view, something as simple as this might work:
def index(request)
get_data = api.getSomeExpensiveData
return render_to_response('template.html', {'get_data':get_data} )
In template
{% block content %}
{% cache 500 "myCacheKey" %}
{{ get_data.something }}
Or maybe
{% for something in get_data %}
{% endfor %}
{% endcache %}
{% endblock %}
Django template automatically calls all callable objects.
EDIT:
If you need to use get_data more than once in your template you'll need some wrapper. Something similar to this:
def index(request)
class get_data(object):
data = False
def __call__(self):
if not self.data:
self.data = api.getSomeExpensiveData()
return self.data
return render_to_response('template.html', {'get_data':get_data()} )
I found this SO - How do I access template cache?
And adapted it to
from django.utils.hashcompat import md5_constructor
from django.utils.http import urlquote
from django.core.cache import cache
def hasFragmentCache(key, variables = []):
hash = md5_constructor(u':'.join([urlquote(var) for var in variables]))
return cache.has_key(cache_key)
Edit - I've accepted skirmantas answer as whilst this does exactly as asked its the better approach as then the template and view are more loosly coupled. Using this method you need to know the name of each cache fragment and whats used where. A designer moves things around and it would fall over.
Related
Say we have a flask template as such:
{% extends "layout.html" %}
{% block body %}
<div class="container page-container">
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</div>
{% endblock %}
We can render this template using the flask.render_template() function, and thus display a flash message using code like this:
from flask import flash, render_template
#timesheet_billing.route('/timesheet-billing')
def timesheet_billing_select_job():
jobs = get_open_jobs()
flash('A job was not selected!')
return render_template('timesheet_billing/index.html', jobs = jobs)
However if we render it using Jinja2's template class function jinja2.Template.render() with code like this:
from flask import flash
import jinja2
env = jinja2.Environment(loader=jinja2.PackageLoader('templates'))
index_temp = env.get_template('index.html')
#timesheet_billing.route('/timesheet-billing')
def timesheet_billing_select_job():
jobs = get_open_jobs()
flash('A job was not selected!')
return index_temp.render(jobs = jobs)
We get the following error when trying to load the page:
jinja2.exceptions.UndefinedError: 'get_flashed_messages' is undefined
What is the difference here? The answer in this question suggests that they should be the same. However it seems in one we do not have access to flask methods.
I believe the difference here is how flask.get_flashed_messages works.
This webpage https://flask.palletsprojects.com/en/1.1.x/templating/ explains the scope of jinja2 context variables:
The Jinja Context Behavior:
These variables are added to the context of variables, they are not global variables. The difference is that by default these will not show up in the context of imported templates.
This is partially caused by performance considerations, partially to
keep things explicit.
Here is where flask's render_template makes a difference, when comparing it to jinja2.render (from the question link you referred to):
def render_template(template_name_or_list, **context):
ctx = _app_ctx_stack.top
ctx.app.update_template_context(context)
return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
context, ctx.app)
def _render(template, context, app):
before_render_template.send(app, template=template, context=context)
rv = template.render(context)
template_rendered.send(app, template=template, context=context)
return rv
by calling render directly, you're missing the application context update call, which will inject all the information a template context processor will need to make functions (like get_flashed_messages, in this case) available to templates.
I am trying to simplify my code by creating a custom template tag for a 'for loop' that use frequently on my Django web application. I thought it would be a simple straight process, but something isn't working right... I can use some assistance in catching my error.
Here is my code.
views.py
class ArticleView(DetailView):
model = Articles
def get_context_data(self, **kwargs):
context = super(ArticleView, self).get_context_data(**kwargs)
context['s_terms'] = scientific_terms.objects.all()
return context
template tag
#register.filter(name='term')
def term(value):
{% for term in s_terms %}
{{ term.short_description }}
{% endfor %}
template.html
{% Neurons|term %}
Thank you for your assistance, in advance.
You are mixing Python code with the Django Template Language. The template tags are plain Python code, as they are defined inside a Python module. A working example would be:
#register.filter(name='term')
def term(terms):
output = ''
for term in terms:
output = '{0} {1}'.format(output, term.short_description)
return output
Then you could use it like this:
{{ s_terms|term }}
Maybe what you want is simply to create a reusable Django template.
For example, create a new template named terms.html:
templates/terms.html
{% for term in terms %}
<p>{{ term.short_description }}</p>
{% endfor %}
Then, in another template, you could include this partial template:
templates/index.html (name is just an example)
{% extends 'base.html' %}
{% block content %}
<h1>My application</h1>
{% include 'terms.html' with terms=s_terms %}
{% endblock %}
I want to pass data from models to template using CMS_plugins.py
I've made an app and standalone works. When i open link manualy
localhost:port/en/post_list.html all values are shown and works.
If i go on admin page and add plugin, values in mysql are stored but not presended in my template.html . I want to pass values in template.html
EDIT:
I manage to pass values to template. I edited cms_plugins.py
How can i hook data with "for" ?.
In code blow, nothing isnt shown in my template.html
<p>{{instance.firstline}}</p> ->>>this works
{ %block content %}
{{ instance.post.offer_option}}
<p>{{post.firstline}}</p>
<p>{{post.secline}}</p>
{% endfor %}
{% endblock}
if i change to :
{% for post in posts %}
<p>{{post.firstline}}</p>
<p>{{post.secline}}</p>
{% endfor %}
{% endblock}
In upper case if i run manualy url: localhost:port/en/pricing , I can see the result i want to be rendered in template.In template nothing isnt shown neither.
cms_plugins.py
class pricing(CMSPluginBase):
model = Post
name = _("pricing")
render_template = "post_list.html"
cache = False
def render(self, context, instance, placeholder):
context.update({'instance': instance})
return context
plugin_pool.register_plugin(pricing)
I want to loop data taken from database in rendered template. Using cms plugin.
I dont have problem looping data in html template. But if i use CMSPlugin to insert new app in placeholder, nothing shows.
If i run url localhost:port/test.html.I got input what i want. But rendered template doesnt loop data.
{% for post in posts %}
{{ post.firstoption }}
{% endfor %}
if I use code below, nothing shows in my rendered template. Values are passed in rendered template. Because, if i try {{instance.firstoption}} i get value shown in template. Problem is i cant loop data with tag instance.
{% for post in instance.posts %}
{{ post.firstoption }}
{% endfor %}
I also tried {% for post in instance.posts_set.all %}
and {% for post in instance.posts.all %}
cms_plugins.py
class pricing(CMSPluginBase):
model = mymodel
name = _("myplugin")
render_template = "template.html"
cache = False
def render(self, context, instance, placeholder):
context.update({'instance': instance})
return context
models.py
class mymodel(CMSPlugin):
firstoption = models.CharField(max_length=200)
def __str__(self):
return self.firstoption
It is probably because you need to call all on your posts
{% for post in instance.posts.all %}
{{ post.firstoption }}
{% endfor }
I'm trying to build a website that has products and categories.
When you are on the page of a product, you can click a button to see a list of all the categories it falls under.
You can click another button, that appears on all pages, to see a list of all the categories overall.
In the html page see_all_categories, I wrote a simple block like this:
{% extends 'base.html' %}
{% load staticfiles %}
{% block content%}
{{Category.all}}
{% endblock content %}
I expect to see a messy printout of all the categories but I don't. It doesn't return an error, but it produces nothing, other than the base.html.
What am I doing wrong?
You want to display a list of the categories. I assume your Category model owns an attribute named "title" which is the representation of your Category.
If you're using Django template engine or Jinja2, you can make a for loop inside your template like this :
{% for cat in Category.objects.all %}
{{ cat.title }}
{% endfor %}
As a troubleshooting, I'd suggest you didn't pass your Category model to your template, that is not done automatically. You have to add your model to the context before rendering the template.
As mentionned in the comments, here is doc for template rendering with Django templates.
Django Template Guide
To add your model to the context you can follow this guide.
I don't intend to help you further because I lack of information and that may vary a LOT according to your settings. (Class Based views ? Function based views ? What kind of template are you using... And so on)
I figured out the solution after many long annoying hours of trying everything. I feel dumb but I want to spare the next guy the massive pain in the two-pack.
This is what I did:
In the Views.py, I changed the view function for this page FROM this:
def view_all_categories(request):
context = {'Category' : Category}
return render(request, 'store/see_all_categories.html', context)
TO this
def view_all_categories(request):
all_cats = Category.objects.all().order_by('id')
context = {'all_categories' : all_cats}
return render(request, 'store/see_all_categories.html', context)
and in the page see_all_categories.html itself, I changed it (from the question) TO this:
{% extends 'base.html' %}
{% load staticfiles %}
{% block content%}
{% for cat in all_categories %}
<p>{{ cat.name }}</p>
{% endfor %}
{% endblock content %}
And now it works!!