Read variables from template in Django or Jinja2 - django

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

Related

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 %

Django template system - getting fields from template

Is there a function that returns a list of fields that are expected in template? For example, I have the following template:
hello i am {{ name }}. {% for i in docs %} i have doc {{ i }}
Written in file. And i want to get a dict which contains:
{'name': 'str', 'docs': 'list'}
Is there something like that or i have to write it by myself?
As far as i know, NO....
Your template contains some html and some place holders (and may be something else). What render_to_template doing is, it gets a context dictionary which contain some keys and some data attached to that keys and a template. Then it places the values to those place holders according to their key names, execute some loops or condition checks if your template contains control flows like {% if...%} or {%for....%}
If TEMPLATE_DEBUG is closed in your settings, and if there is a place holder with no matching key in your context dictionary, then it will skip that without raising any error.
Also, if you pass a form object to your template and place your object directly to template as it is (without calling each field separately) [ex: {{form}} or {{form.as_p}} then django will check for fields on the form and palce them as it is shown here. In a such situation, you will only know that form is used. You have to check which fields are used from your Form definition.
If you look through that process, you must know what you need to place your context dictionary. You may write a parser to parse your template but it is far more difficult than just examining the template and find missing data, i guess.
The builtin {% debug %} tag may be helpful for you, however I don't know if I fully understand what you are asking. Basically, if you put the debug tag in your template it will print a lot of useful stuff, including all the variables available in your template.
Perhaps you could take a look at the source code for the debug tag (because they have access to all the variables there), and build a custom tag tag based off of this. Taking a glance at the source, this seems like it would be really simple to do.

How to make a dynamic menu in base template using django

I'm about to start a new project and I think this time django is the way to go. I've been reading the documentation for the past two weeks and it looks promissing.
Ok, the thing is that I could not find anything about (in C# MVC called) Partial Rendering. For example if I want a dynamic menu where the menu-items comes from the database, then I would expect that the base template (or master page) renders the menu on each request (the partial renderer invokes another action or renders a template with some session data). So, the menu comes for free as long as my template inherits from this base template.
Honestly, I have no clue on how to achieve this.
What I would like is some code in the base template that uses data that is not contained in the child template. I don't want to include an extra variable (maybe 'menu_list_items') every time I call render_to_response('child_content.html',context). Is this possible?
Thanks!
You could either use a context processor, or a custom template tag to provide this functionality.
A context_processor is a simple function which can add objects to every RequestContext. A custom template tag can have its own template snippet and context which could render the menu for you.
For the template reusing: you should just create a base template for the generic layout, and use detailed templates for the individual pages. This is already covered in detail by the Django documentation.
What I tend to do for those generic parts (say for example, a menu highlighting the current part of the site the use is on), is to create my own render_to_response functions, akin to the following:
from django.shortcuts import render_to_response as django_render_to_response
def render_to_response(template, params, context_instance):
return django_render_to_response(template,
AppendStandardParams(request, params),
context_instance)
The ApplyStandardParams method then configures the menu based on the current path:
def AppendStandardParams(request, params):
if request.META['PATH_INFO'].startswith('/customer'):
params['category'] = 'customer'
params['title'] = 'Customer overview'
# and so on for all different parts
These category and title tags in this example are some values used to highlight the menu, configure titles, and so on. For example:
<!-- Customer menu entry: change class if this is the current category. -->
<li{% if category == "customer" %} class="selected"{% endif %}>Customers</li>
Finally, to use it in a view, instead of the normal render_to_response import, I just do something like from lib.views import *, which makes my custom version available in the view. This way the syntax of all code in the views stays the same, but I don't have to customize the menu every time I create a new view or app.

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>)

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

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!