Can I have a route that renders a template that I can use in another template?
I imagine something like
#app.route('/tags/')
def tags():
return render_template('tags.html', tags=create_tags())
and then somehow invoke the route from a different template.
<h2>Tags</h2>
{{ render('/tags/') }}
Routes don't render templates, functions do. All the route does is point a url to a function. So, the obvious solution to me is to have a function that returns the rendered tag template:
def render_tags_template():
return render_template('tags.html', tags=create_tags())
Then we want to associate the function with the url "/tags"
app.add_url_rule('/tags', endpoint='tags', view_func=render_tags_template)
We also want to be able to access this function from within our templates. Accessing it via the url through another request would most likely be a job for ajax. So we have to get render_tags_template into the template context.
render_template('some_random_template.html', render_tags_template=render_tags_template
then in your some_random_template.html:
{{render_tags_template()}}
if you don't want to pass render_tags_template explicitly, you can add it as a template global:
app.jinja_env.globals['render_tags_template'] = render_tags_template
and use it freely in all of your templates, without having to pass it explicitly.
Depending on what your actually trying to do, simply including tags.html may be the best and easiest solution. Using a function to generate the content gives you a bit more control and flexibility.
You can include the tags.html template in your template.
{% include "tags.html" %}
You have to pass the tags to your template, but this is the way to do it.
Related
I have a table with results from a search. This means there are no models here. The problem is that i'd like to go to a detail page for a clicked item, but I am not sure if I can do that without putting it in the URL.
Right now it is done like this:
In my .html for each item in the table:
view more</td>
In my urls.py
url(r'^track/(?P<title>.+?)/$', detail,
name='detail'),
In my detail view, where it uses the variable:
def detail(request, title):
if request.method == 'GET':
...
Now this might work, but it is not ideal for me. The url contains whitespace and is not urlencoded, because I need the variable like it is. I was wondering if there is some easier, or better way to pass this variable to a different view or template
The right way to do this is to define a get_absolute_url method on the model class for your item model. This is typically done using reverse, so it would look something like this:
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('detail', kwargs={'title': self.title})
Then in your template you simply do:
view more
And the title will be properly escaped.
That said, you might want to consider using a slug instead of a title to generate your URLs.
I've tried to build the simplest possible form in Sprox using pyramid.
# model.py
class Allocation:
# some fields ...
class SproxForm(AddRecordForm):
__model__ = Allocation
sprox_form = SproxForm(DBSession)
# views.py
def sprox_form(request):
return {'f':sprox_form,'kw':{}}
<html>
<body>
<div tal:content="structure f(kw)"/>
</body>
</html>
But it just prints out {'kw': {}, 'f': } The forms tutorial is written using TurboGears2 and I am unable to translate it to pyramid, because I am new to pyramid.
So could someone tell me what am I doing wrong, or show me a short (but complete) example, which uses pyramid?
Well your form is named sprox_form and your view is named sprox_form. This ambiguity is gonna be a bad idea. Other than that I can't see anything suspicious, assuming your chameleon syntax is correct. If you were using mako it'd be simply ${f(kw)} although instead of f I might suggest using the name widget or form, and instead of kw maybe value or form_input.
When passing an object called widget as part of the context to rendering a django template, I may have a method which is a bit expensive, but I want to display the result of it more than once.
Python:
class Widget:
def work(self):
# Do something expensive
Template
This is a widget, the result of whose work is {{widget.work}}. Do
you want to save {{widget.work}} or discard {{widget.work}}?
Clearly I could work around this by evaluating the method once in the view code, and then passing the result in, but this seems to couple the view and the template too much. Is there a way for the template author to stash values for re-use later in the template? I would like to do something like this:
{% work_result = widget.work %}
This is a widget, the result of whose
work is {{work_result}}. Do you want to save {{work_result}} or discard {{work_result}}?
Does such a construct exist in the django template language?
{% with %}
{% with work_result=widget.work %}
Look Django docs for more information
I've got a filter currency, which takes a value in USD and converts it to a currency (either USD or GBP). The currency to convert to is stored in the session, but filters don't take RequestContext, so I can't grab it straight from there.
Is there a better way than passing the relevant session element into the template, and from the template into the filter as an argument? Whilst this approach is working, it seems fairly horrible, and I'm likely to end up passing the currency to (almost) every template.
My filter currently looks something like this:
def currency(value, currency):
if currency == 'usd':
val = '$%.2f' % value
return mark_safe(val)
d = Decimal(value)
val = '£%.2f' % (d*Decimal('0.63'))
return mark_safe(val)
If you create a template tag instead of a filter, you are given the context to work with (which contains the request). http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags
I would have to agree with Adam that migrating the code to a custom tag is the best way.
However, a client needed to record the use of certain filters only when a page was published and had a HUGE inventory of templates that used the existing filter syntax. It would have been a costly undertaking to rewrite all the templates. So, I came up with this simple function that extracts the context from the call stack:
https://gist.github.com/drhoden/e05292e52fd5fc92cc3b
def get_context(max_depth=4):
import inspect
stack = inspect.stack()[2:max_depth]
context = {}
for frame_info in stack:
frame = frame_info[0]
arg_info = inspect.getargvalues(frame)
if 'context' in arg_info.locals:
context = arg_info.locals['context']
break
return context
Be sure to read my warnings, but this DOES give standard filters access to the context (when it is available) WITHOUT having to turn your filter into a tag.
This can be done using a filter. First make sure that you have "django.core.context_processors.request" in you TEMPLATE_CONTEXT_PROCESSORS. If you don't, you can add this to your settings.py file:
TEMPLATE_CONTEXT_PROCESSORS += (
"django.core.context_processors.request"
)
Then in your template, your filter will look like this (assuming your session variable is named 'currency_type'):
{{value|currency:request.session.currency_type}}
Or is something like this what you are considering fairly horrible?
A somehow less hacky solution to Daniel Rhoden's proposal is, to use threading.local(). Define a middleware class, which stores your request as a global object inside your local thread, and add that class to your MIDDLEWARE_CLASSES.
Now a template filter can easily access that request object.
I am currently working on an app that uses custom annotate querysets. Currently i have 2 urls setup, but i would need one for each field that the users would like to summarize data for. This could be configured manually, but it would violate DRY! I would basically have +-8 urls that basically do the same thing.
So here is what i did,
I have a created custom model manager
I have a view
I have the URLS configured
All of the above works.
So basically the URL config passes to the view the name of the field to annotate by (group by for SQL folks), the view does some additional processing and runs the custom model manager based on the field that was passed to it.
The URL looks like this:
url('^(?P<field>[\w-]+)/(?P<year>\d{4})/(?P<month>\d+)/(?P<day>\d+)/$','by_subtype', name='chart_link'),
The field is the column in db the that is used when the queryset is actually run. It is passed from the view, to my custom manager. Below is an example of the code from the manager:
return self.filter(start_date_time__year=year).filter(start_date_time__month=month).filter(start_date_time__day=day).values(field).annotate(Count(field))
In addition, i pass the value of field as context variable. This is used to dynamically build the links. However the problem is actually looping through the query set and displaying the data.
So your typical template code looks like this:
{% for object in object_list %}
{{ object.sub_type }} : {{ object.sub_type__count|intcomma }}
{% endfor %}
Basically you have to hard code the field to diplay (i.e object.x), is there anyway to dynamically assign this? i.e
if field = business
then in the template it should automatically process:
{{ object.business }}
Can this be done? Or would i need to create several URLS? Or is there a better way to achieve the same result, a single view and url handling queries dynamically.
You can find the code over at github, the template part is now working using this snippet: http://www.djangosnippets.org/snippets/1412/ So if you come across this later and want to do something similar have a look at the code snippet at github. : http://gist.github.com/233262
It sounds like you want to do something along the lines of:
# in the views.py:
field = 'business'
{# in the template: #}
{{ object.field }}
and have the value of object.business appear in the output. This isn't possible with the Django template language out of the box.
There are snippets that define template filters you can use to accomplish this though: http://www.djangosnippets.org/snippets/1412/
As mentioned above, you can do this with a custom template filter.
For example:
#register.filter(name='get_attr')
def get_attr(obj, field_name):
if isinstance(obj, dict):
return obj.get(field_name)
return getattr(obj, field_name)
Then, using it in your template:
{{ obj|get_attr:'business' }}