How can you use Django template tags in a Jinja2 template? - django

There are a number of off-the-shelf Django packages that offer template tags, and I'd like to use them in my project despite the fact that it uses Jinja2.
I've seen some workarounds that allow other template engines to use Django tags. These involve creating a mini-template in a string, and passing it to the Django template processor along with the current context. Here are two example of what I'm talking about: Mako templates using Django template tags and Jinja2 templates using Django template tags.
I'm wondering if there's a less hackish solution.

what about moving problem to python's scope
and importing one python's function into another, this way:
in your_jinja_templatetags.py
from some_django_templatetags import somefilter as base_somefilter
#library.filter
def somefilter(value):
return base_somefilter(value)

Unfortunately Django template tags are not directly translatable to Jinja.
Django Template tags can do many different things, and are usually implemented as functions. Fortunately, Jinja can register these functions as globals and call them. This works for "simple" template tags out of the box.
If you are using the official Django Jinja2 backend, see https://docs.djangoproject.com/en/4.1/topics/templates/#django.template.backends.jinja2.Jinja2 to find out how to register a function (in this case your template tag) as a global. Once this is done, you can call the function from within your template as {{ your_tag_function() }}. Remember to pass whatever arguments the template tag function needs!
I like to use the https://github.com/niwinz/django-jinja backend, myself- if you are using this backend, see https://niwi.nz/django-jinja/latest/#_custom_filters_globals_constants_and_tests for how to register a function as a global.
Unfortunately, this only works for "simple" tags out of the box. Some tags are "inclusion tags" or otherwise depend on the Django Template Engine. Since Django Templates can't be rendered within the Jinja engine, you have to do a bit more work to translate these types of tags. You will need to look at the source code to tell the difference and see what they are doing.
What I usually do for the more complicated tags is create a "jinja_functions.py" script in my Django app, then in that script I import the original template tag. Then I write a function that wraps it- calling the original function, getting back usually a dictionary, and then using that dict to render a string which is returned... most tags are simple enough I just use an f string or .format to format them with the results of the dict.
Then I register my new wrapper function as a jinja global and use it in my jinja templates!
The following is an example of where I re-implemented the template tags provided by https://github.com/timonweb/django-tailwind for use with jinja. I combined both the tailwind_css and tailwinf_preload_css tags into a single function, tailwind_css, which I register with Jinja as a global as per the instructions above, then I can call that function as {{ tailwind_css(prefetch=True) }} or {{ tailwind_css() }} within my templates.
from django.templatetags.static import static
from tailwind import get_config
from tailwind.utils import is_path_absolute
def tailwind_css(v=None, prefetch=False):
tailwind_css_path = get_config("TAILWIND_CSS_PATH")
if not is_path_absolute(tailwind_css_path):
tailwind_css_path = static(tailwind_css_path)
if v:
tailwind_css_path = f"{tailwind_css_path}?v={v}"
if prefetch:
rel = 'rel="preload"'
as_str = ' as="style"'
else:
rel = 'rel="stylesheet"'
as_str = ""
return f'<link {rel} href="{tailwind_css_path}"{as_str}>'
In conclusion it works well out of the box for "simple" tags because you can just register them as global functions in Jinja... but for "include" tags or other tags that rely on the Django Template engine, you will have to write your own function :( But usually its not too much work!

Related

Read variables from template in Django or Jinja2

Looking for a solution to read the complete list of variables that can be passed into a context and displayed within a template, using either Django or Jinja2.
For example, something like this in Django:
from django.template import Template
template = Template("<h1>{{title}}</h1>{%for v in values%}<p>{{v}}</p>{%endfor%}")
for node in template.nodelist:
#Get the variable name from the node
This seems like a real pain. All I want is a list of the keys that a context object could pass to the template, in this example, "title" and "values"
You could use {% debug %} tag
debug
Outputs a whole load of debugging information, including the current
context and imported modules.
Also if you want even more you could use Django debug toolbar

Conditional tags in templates

I'm using Django on top of an existing database/user framework so unfortunately it is not possible to me for use the django auth framework.
I have my custom auth library built, now I just need to figure out how to use it in templates. Certain links should only appear for users who have access to it.
In PHP I could do soemthing like this
<?php if auth('RestrictedLinkName') {?> <?php } ?>
What is the Django way? I have been playing with custom tags but haven't been able to get it working yet. I was thinking something like:
{% if check_permission('Restrictedarea') %} hjkfgdkhfg {% endif %}
If you need to evaluate check_permission('Restrictedarea') then do it in the view function and pass the evaluated result in the template.
The djangobook says (in Chapter 4: Templates, in Philosophies and Limitations section) -
Business logic should be separated from presentation logic. Django’s
developers see a template system as a tool that controls presentation
and presentation-related logic – and that’s it. The template system
shouldn’t support functionality that goes beyond this basic goal.
For that reason, it’s impossible to call Python code directly within
Django templates. All “programming” is fundamentally limited to the
scope of what template tags can do. It is possible to write custom
template tags that do arbitrary things, but the out-of-the-box Django
template tags intentionally do not allow for arbitrary Python code
execution.
And if need to write custom tags check these links:
Writing a Template Tag in Django
Custom template tags and filters
You can write your custom template tags and filters. But this may help you up to a point, for further, you must write your custom context_processors (and custom middlewares if needed.)
But doing authentication and permission check through custom function is quite hard, but possible. I have a system fully runs on custom authentication/authorization.
First of all, you can examine django context_processors to understand how they work. then you can write your custom context_processor. After you add your context processor in your settings, you can use those methods, and do your authentication/authorization as you wish.
One of my custom contect_processor function is like:
from django.utils.functional import lazy
def CustomProcessor(request):
cust_perms = {
'admin_perm_check': lazy(lambda: myCustomPermChecker(request), myCustomPermChecker)(),
'system_admin': aFunctionToReturnBoolValue(),
}
return custom_perms
class myCustomPermChecker(object):
def __init__(self, request):
self.request = request
def __getitem__(self, perm_name):
return True if (perm_name in user_perm_list()) else False
In your template
{%if admin_perm_check.perm_name%}...{%endif%}
{%if system_admin %} this is a bool check{%endif%}
You must define your permchecker as a class, which have __getitem__ method so, your template tag admin_perm_check.perm_name could work. This perm checker accepts only one additional paramater (perm_name), If you want to use django-style two parameter check then you must do:
class myCustomPermChecker(object):
def __init__(self):
pass
def __getitem__(self, module_name):
return SecondPermCheckerStep(module_name)
class SecondPermCheckerStep(object):
def __init__(self, module_name):
self.module_name = module_name
def __getitem__(self, perm_name)
return True if ('%s.%s' % (self.module_name,perm_name) in user_perm_list()) else False
{%if admin_perm_check.module_name.perm_name%}
You can use another class.__getitem__ to add one more key to tour tag chain in your template etc.
Since your context_processor CustomProcessor(request): accept http.request object as a parameter, you can pass your methods or functions any value (session id or user id etc.) that will be required in authenticaon or authorization. You can write a middleware to set custom values to your request object to use (like django set user instance and let you use request.user in your views.). You can also set your custom user model instance so you can use it in you template (if you set it in your request_context) and in your views (if you set it in your middleware)
Reading docs could not help here much, better is checking django code to see how django handle this.

Django's equivalence of ASP.NET UserControl

If anyone here is ASP.NET pro, you might know what I mean by user control. I wish to create a similar one in django instead.
So, my problem is that I have several pages in my website, but I need a search bar to appear in every pages. Since I require the views.py to operate this search bar, I cannot do a simple method of
{% include 'something.html' %}
Therefore, can anyone suggest how can I do it?
There are a couple of ways to accomplish what you're wanting to do:
Context Processors
Template Tags
Context Processors can augment the template context with values, regardless of which template is loaded. They are akin to filters in Rails.
Template Tags, like Context Processors, can accomplish anything you can do in Python, but are implemented at the template level.
If you need something to be present on every template, one of the simplest ways to accomplish this is with an inclusion tag, which can also accept values passed to it. An inclusion tag could be implemented at your highest level template, a.k.a your MasterPage, and as long as you don't put it in a block and override it, it would appear on every page that includes that template in its inheritance chain.
If it's just something you want to include on every page, and it doesn't need to do any processing, you should just be able to place the code you want in the top-most template and have subsequent templates inherit that.
I typically have a "base.html" template that all of my templates inherit from. If I need something to be in every page, I put it there. If it's something I want there by default, but want to be able to augment it in subsequent templates, I will place it into a block. That block will let you include or override its default content.
I know this post is kind of old but I just came across it and found a kind-of-solution that works. I call it kind-of-solution because it is a workaround.
I have a few different sites on which I want to display logging information. This display always looks the same (it has the same html) and has the same database table and model class behind it.
My solution/workaround uses the django filters:
in views.py I put the list of log-entries in the context
context = {'list_log': Log.objects.filter(condition = True) }
template = loader.get_template('my_html_file.html')
return HttpResponse(template.render(context, request))
in my_html_file.html I use a custom filter
{{ list_log|get_log_uc|safe }}
in the filters.py I load another html file with this custom filter
#register.filter
def get_log_uc(list_log):
template = loader.get_template('user_control_log.html')
context = { 'list_log' : log }
return template.render(context)
in user_control_log.html I have the user control equivalent html
{% for log in list_log %}
<p>log.something</p>
{% endfor %

Database localization in Django

I am using .mo files for localization in Django.
Also, in my database, I store some translated text in different fields, such as:
name_en, name_es, name_de (they are all columns in each row).
What will be the best method to choose the correct field inside a template?
i.e.:
{{ name.some_method }} will generate the correct translation based on the current localization.
Thanks,
Meit
You should look at http://goodcode.io/articles/django-multilanguage/ Here’s a simple solution that may fit your use case and is easy to implement and understand.
You should look at Django Transmeta, it work the same way as what you've done (DB fields with language code) but it's a more complete solution. It already deal with the template stuff, etc.
You can check Model Internationalization and Django Packages for more info and ideas in this domain.
I can see two method for doing this, one in your view and the other one is in the template...
In view:
Probably you keep the user language information somewhere so,
user_lang = 'es'
obj = Somemodel.objects.get(pk=123434)
obj.local_name = getattr(obj, 'name_%s'%user_lang)
So, you keep local translation in a specific variable of the instance and in your template you can use is as:
{{obj.local_name}}
But that might be costly if you wish to pass the template a queryset instead of a single instance. For a such usege you have to evaluate that value for each object in your queryset.
In template:
That is a more complex way of solving the porblem in the template...
Define a template tag and pass object_id, and local language information and get the translated text using a similar getattr function. But in that point, if you wish to use this for more than one model, you probably have to pass a content type information for your template tag too, such as:
{% get_translation <object_id> <content_type_id> <local_language> %}
And in your template tag function, do something like:
from django.contrib.contenttypes.models import ContentType
....
cont_obj = Content_type.objects.get_for_id(<cotent_type_id>) #get the related model
obj = cont_obj.get_object_for_this_type(pk=<object_id>) # get your object
return getattr(obj, 'name_%s'%<local_language>)

Django tags and filters in Lift?

This is a generalization of my previous question about pluralize filter:
Does lift have an equivalent of Django's tags and filters?
Tags are small piece of predefined code that can be used directly in html template, for example:
{% now "jS F Y H:i" %}
renders the time right now in the given format.
Filters
Filters operate (in html template) on the context variables in the template, for example:
{{ value|capfirst }}
if called on a value "john" will result in "John". Or:
{{ value|length }}
will render the length of the string into the template.
As you can see the filters operate on the context variables that are passed to the template.
Considering tags, you could define those yourself with snippets.
As snippet is basically a callback much as a Django tag is. You don’t get any easier syntax, though, because Lift’s templates are pure XML/Html.
<Lift:Tag.now format="jS F Y H:i" />
And the logic would be defined in
class Tag {
def now: NodeSeq = // ...
}
Filtering is something you generally can’t do in a Lift template because Lift doesn’t allow any variables in a template. The whole concept is thus inapplicable. (You could do XML transforms or or bind magic but that would be a bit too much for a simple value.length.)
No, if you need the length of some value in your Html, you will have to define that inside the snippet and expose it.
If you really can’t live without filters in your template (though I can assure you, it is a good thing to separate all HTML template and code and it works once you are used to it), have a look at Scalate which may be used together with Lift as well.
This kind of logic should be in the render method of a snippet. Display code in pure Scala (rather than in a template language hybrid) is a first-class citizen with respect to testing, IDE's and refactoring tools.
These kinds of transforms don't come built-in, but you can add them with implicits:
class HappyString(s: String) {
def capfirst = ....
}
implicit def toHappyString(s: String) = new HappyString(s)
Then call these in your render method before binding whatever value it is you're generating.