Get the source of a Django template - python

I need to get the source of a template. I looked into the template APIs and into the source code with no success.
Apparently, the Template object keeps no reference to the original source.
Before messing up my codebase I'm asking: is there a simple way to get the source of a template?

The Template objects don't keep a reference to the original source, but they do keep a reference to the original source file and you can re-read the source from there:
source = open(template_instance.origin.name, 'r').read()

If you know exactly what loader is loading template you can use Loader method directly.
from django.template.loaders.app_directories import Loader
source = Loader.load_template_source(file_name)[0]
file_name is same as when loading templates with loader.get_template(file_name)

There is a great shortcut called render_to_string.
As de docs says:
It loads a template, renders it and returns the resulting string:
from django.template.loader import render_to_string
rendered = render_to_string('my_template.html', {'foo': 'bar'})
So, the variable rendered is a string with the source code of the template

Templates are text files (usually, HTML, but not necessarily) that get rendered with a context (usually) when called from a call to, for instance, django.shortcuts.render. If you have a view function, that should specify which template it's using.
From the docs:
from django.shortcuts import render
def my_view(request):
# View code here...
return render(request, 'myapp/index.html', {"foo": "bar"},
content_type="application/xhtml+xml")
Here, the template would be "templates/myapp/index.html".

Related

Fetching a mobile or desktop template using django middleware [duplicate]

I want to write custom template loader for my Django app which looks for a specific folder based on a key that is part of the request.
Let me get into more details to be clear. Assume that I will be getting a key on every request(which I populate using a middleware).
Example: request.key could be 'india' or 'usa' or 'uk'.
I want my template loader to look for the template "templates/<key>/<template.html>". So when I say {% include "home.html" %}, I want the template loader to load "templates/india/home.html" or "templates/usa/home.html" or "templates/uk/home.html" based on the request.
Is there a way to pass the request object to a custom template loader?
I've been searching for the same solution and, after a couple days of searching, decided to use threading.local(). Simply make the request object global for the duration of the HTTP request processing! Commence rotten tomato throwing from the gallery.
Let me explain:
As of Django 1.8 (according to the development version docs) the "dirs" argument for all template finding functions will be deprecated. (ref)
This means that there are no arguments passed into a custom template loader other than the template name being requested and the list of template directories. If you want to access paramters in the request URL (or even the session information) you'll have to "reach out" into some other storage mechanism.
import threading
_local = threading.local()
class CustomMiddleware:
def process_request(self, request):
_local.request = request
def load_template_source(template_name, template_dirs=None):
if _local.request:
# Get the request URL and work your magic here!
pass
In my case it wasn't the request object (directly) I was after but rather what site (I'm developing a SaaS solution) the template should be rendered for.
To find the template to render Django uses the get_template method which only gets the template_name and optional dirs argument. So you cannot really pass the request there.
However, if you customize your render_to_response function to pass along a dirs argument you should be able to do it.
For example (assuming you are using a RequestContext as most people would):
from django import shortcuts
from django.conf import settings
def render_to_response(template_name, dictionary=None, context_instance=None, content_type=None, dirs):
assert context_instance, 'This method requires a `RequestContext` instance to function'
if not dirs:
dirs = []
dirs.append(os.path.join(settings.BASE_TEMPLATE_DIR, context_instance['request'].key)
return shortcuts.render_to_response(template_name, dictionary, context_instance, content_type, dirs)

How does a django render function know where this file is located?

Right so I am following a long a python Django tutorial and I am confused on how this
render function knows where index.html is. The file I am in is views.py.
from django.shortcuts import render
from appTwo.forms import NewUserForm
def index(request):
return render(request,'appTwo/index.html')
The file structure looks like
It doesn't "know" per se, but it does scan all template directories you list in settings.py as described here. The first that matches the name you provide is used.

What is the difference between render() of DjangoTemplates class and render() method found in django.shortcuts module?

I am trying to learn Django. I am creating a small applicationt to understand its basic functionalities. In views.py of a django app, some tutorials use render() from template while others use render() from django shortcuts module.
For instance, in views.py
from django.shortcuts import render
def home(request):
context = {}
template = "app/add_item.html"
return render(request, template,context)
and yet others,
from django.http.response import HttpResponse
from app.models import Items # this is the model
def home(request):
item_list = Items.objects.order_by('-item_name')
template = loader.get_template('app/add_item.html') # could be index.html as well
context = {
'item_list': item_list,
}
return HttpResponse(template.render(context, request))
What is the difference between render() method of DjangoTemplates class and render() method found in django.shortcuts module? Which one should I prefer and why?
django.shortcuts.render is, as its name implies, a shortcut for returning a rendered template as a response from a view. Its use is rather limited to that context. It takes an HttpRequest instance as its first argument and its main purpose, per the docs, is to
combine a given template with a given context dictionary and returns an HttpResponse object with that rendered text.
Importantly, this selects a template by name. It is intended to select a template for rendering and returning as a response.
Template.render is part of the low-level template API and takes the single template, represented by that object, and renders it to a string.
Importantly, this takes only the template already represented by your object. It has no mechanism for discovering another template to render.
Generally, the shortcut version is the most useful, as quite often you want to return a rendered template as a response from your views. This is the whole reason it exists.

Python django, is possible to present the output of a view directly in a html template?

Let's suppose you have a django project, the response of one of its views is an image, if you want to insert that image inside an HTML document you do:
<img src="/path_to_my_view/">
Then, when the user open the Webpage that return that HTML document he will see the image. Nothing new at this point.
Now, what happens if the response of that "view" is not an image but a simple text, there is no HTML tag to embed a simple text, so, how would you do it?
The view code that return a simple text is:
from django.http import HttpResponse
def view(request):
return HttpResponse('Simple line of text returned by my view')
So, what I would like to do in my html is something like this:
<p>The exit of the view was: <?HTML_TAG? src="/path_to_my_view/"></p>
Or something like this (using Django template language):
<p>The exit of the view was: {{ MyProjectApp.view }}</p>
But I have not found any one of those alternatives yet.
The current solution to the problem is by using the object HTML tag:
<object width="400" height="400" data="/path_to_my_view/"></object>
However I'm not happy with this solution, it seems like using a cannon to kill a bug, I think that I'm missing something.
Thank you for your support!
I think you are looking for an <iframe>, which is the way of embedding one HTML document inside the other:
<iframe src='/path_to_my_view/'>
However since these are both views on the same server, I don't know why you want to embed it via HTML. Why not simply call the view from your other view and pass the result as a context variable? Or, even better, factor out the code whose result you want into a common method, called by both views.
You have 2 choices here: either you use a TemplateView that you map directly to your url and in that template you add your html code.
The other solution is to interpret a string as a template and render it.
I found a solution to my question:
View.py
def myview(request):
content ='Hello I am an innocent string'
response = HttpResponse(content, content_type='text/plain')
return response
template.html
<object type="text/plain" data="/myapp/"></object>
Hope it helps someone else!
Bye!

Get template name in template tag ( Django )

is there a way to get the template name ( being parsed ) in a template tag ?
I have read searched and found nothing, only this previous post
Getting the template name in django template
which doesn't help me much, since the answer relies on settings.DEBUG being true, which in my case can't be.
I don't really know where to start on this one, so any suggestion is welcome :)
EDIT
So basically what i want is to create a plugable tag that when rendered it checks for a Tag object, this would be the source for the tag object
class Tag(models.Model):
template = models.CharFIeld(max_length=50)
name = models.CharField(max_length=100)
plugins = models.ForeignKey(PluginBase)
if theres a tag object, then it displays all plugin objects, if not it creates a tag object unique to the name provided in the template tag and the template name, if getting the template name is not possible, then i guess i can just make it unique per name. The whole tag is kinda like a placeholder, for those familiar with django-cms
You could perhaps do this with a context processor, but I'm not sure if these have access to the name of the template.
What will work is to make a wrapper for the rendering calls you do. Say you currently do the following:
from django.shortcuts import render
def index(request):
return render(request, 'app/index.html', { 'foo': 'bar', })
If you create your own wrapper for this, you could add the template name to the dictionary before the actual render takes place:
from django.shortcuts import render
def myrender(request, template, dictionary):
dictionary.update({'template_name': template})
return render(request, template, dictionary)
Then in your views, change it as follows (assuming you saved the above function in myutils.py, and it is available on your path):
#from django.shortcuts import render <- delete this line
from myutils import myrender as render
def index(request):
return render(request, 'app/index.html', { 'foo': 'bar', })
Now all your render calls will update the dictionary with the template name. In any template, then just use {{ template_name }} to get the name. You can of course also update other rendering function like render_to_response and such in a similar fashion.
Also, the import myrender as render might or might not confuse you later on because it is named like the Django function... if so, just import it without the "as render", and replace all render calls with myrender. Personally I'd prefer this since this makes it a drop-in replacement for the existing rendering functions.
Looking at the source, while the Template object would have access to the template name (via .name) this value is never passed on to the Parser object and therefore not available to template tags.
There are various ways of making the template name available to the template itself (by adding it to the context) but not within the template tags.
As Daniel Roseman mentioned in the comments, if you can elaborate on what you're actually trying to achieve, there may be a better way to achieve what you want. No offence, but this sounds like it may be an XY problem.
Out of academic interest, I had a quick fiddle to see if it was possible. As far as I can see, it is possible but not without changing or monkey patching the django source.
Note: the following is not a recommended solution and merely hints at what may be required to actually make this work. Not to be used for production code.
By modifying django.template.base.py with the following changes, we add the .template_name attribute to the parser object making it available to template tags.
Added optional arg to compile_string
Added template name as extra attribute to parser
Passed in the template name when calling compile_string()
To test this out, I defined the following tag which simply returns the template name in caps:
from django.template.base import Node, Library
register = Library()
class TemplateNameNode(Node):
def __init__(self, template_name):
self.name = template_name
def render(self, context):
return self.name.upper()
#register.tag
def caps_template_name(parser, token):
return TemplateNameNode(parser.template_name)
and the following template:
{% load mytags %}
Template name in caps: {% caps_template_name %}
This seems to work when tested in ./manage.py shell:
>>> from django.template import loader, Context
>>> t = loader.get_template("test.html")
>>> t.render(Context({}))
u'\nTemplate name in caps: TEST.HTML\n'
While this seems to work, I should reiterate that manually patching the django source never a good solution and is subject to all sorts of misery when migrating to different versions.

Categories