How do include a dynamic template from another app in Django? - django

I currently have two apps:
app1/
app2/
templates/
app1.html
app2.html
In app1.html, I'm including app2.html:
<!-- app1.html -->
{% include "app2.html" %}
app2 has some dynamic content:
<!-- app2.html -->
{% app2_value %}
When I display app1.html, the value app2_value doesn't show up. What's the best way to handle the above in Django?

Django doesn't really process dynamic including like PHP or other languages do. Instead, you should have a base template, and use template inheritance and blocks to accomplish what you're trying to do.
So your app2.html would have the same dynamic content, but have a place for app1.html to either override or insert things.
app2.html:
{% block 'title' %}
{{ app2.title }}
{% endblock %}
{% block 'content' %}
{% endblock %}
App1's template can then extend App2's:
app1.html:
{% extends "app2.html" %}
{% block 'title' %}
Actually App 1!
{% endblock %}
{block 'content' %}
...
{% endblock %}
Unfortunately, include-handling is still new in Django and against best practices from what I've seen in the documentation and community.

In Django your views and your templates are decoupled from each other, so when you use {% app2_value %} in a template it will assume that was passed to it from the calling view.
So, to answer your question, to get that value to display, pass it to app1 template in whatever view you use to call it:
# app1 views.py
from django.shortcuts import render_to_response
import app2
def app1_view(request):
return render_to_response('app1.html', {'app2_value': app2.somevalue})

You can actually render a temple as a string and then send it to another template to be displayed. You would still need to send the variabels to the template you are rending as a string. A good use case would be to use the same template to render list or dicts in a special way.

Related

How to pass the context to a Django template with include?

I have started building a django project from the tutorial at https://docs.djangoproject.com/en/2.1/intro/tutorial01/
After finishing the base tutorial which creates a project with one app called "polls" I wanted to build a sort of home page that can hold many apps together. For this reason I built an app called "news" and now I'm looking at ways to compose the two apps together.
So far I'm doing so in the main 'news' template, which is called 'news/base.html' and I'm including the different apps in the code.
This is my 'news/base.html' file:
{% include 'news/index.html' %}
{% include polls_template %}
{% include 'news/footer.html' %}
The two templates 'news/index.html' and 'news/footer.html' are just html pages with no arguments, just for testing and they work fine.
The polls_template variable instead is a template variable that I create in the news.views.base function and pass to the template in the context.
This is the view snippet that does this:
def base(request):
t = loader.get_template('polls/index.html')
return render(request, 'news/base.html', {'polls_template': t})
The template is showing just fine but it shows an empty poll since there is no argument. Now my problem is that I cannot find a way to pass a context variable to this template object in order to fill it's fields.
I tried to do something like:
{% include polls_template with context=polls_context %}
But it does not work.
Ideally I would like a way to do all of that in the view because this would allow me to build the apps separately and then just use one view to gather them all and pass them to a template. Thanks in advance for any help!
Possible duplicate of Django - two views, one page (disregard the references to Ajax.) One quick note: I see what you are trying to do, but you should understand that render() is a shortcut that includes both the template loading and the HttpResponse(). You don't need to call loader() if you are using render(). Another problem with your function, you've included the template within the context dict. Please read the linked post b/c there are a number of different approaches but for the sake of completeness, here's one way to approach what you are trying to do. First, typically you'd create a 'base.html' file that would be the container for your content, it would include header, footer and possibly the messaging templates. You could then extend the base.html and include other templates.
'base.html'
<!doctype html>
<html lang="en">
<head>
{% include 'header.html' %}
<body>
{% include 'news.html' %}
{% block content %}
//to be replaced by index/polls content that extends this template//
{% endblock %}
</body>
{% include 'footer.html' %}
</html>
'index.html'
{% extends 'base.html' %}
{% block content %}
<ul>
{% for question in questions%}
<li> {{question}}</li>
{% endfor %}
</ul>
{% endblock %}
'news.html'
<ul>
{% for article in news %}
<li> {{article}}</li>
{% endfor %}
</ul>
And then your function
def index(request):
polls_questions = Question.objects.all()
newest_articles = Articles.objects.filter(post=OuterRef('pk')).order_by('-created_at')
return render(request, 'index.html', {'questions' : polls_questions, 'news': newest_articles})

Django - Dynamically include JS/CSS based on installed apps

Does anybody know a way to adjust the included JS/CSS resources in a template based on the apps you've installed?
Let's say we have a basic feature in app x using template.html, and this requires foo.js which is provided in the static files for the app.
What I'd like is a way of saying an additional and optional app y can register bar.js to be included in template.html as well and this provides some advanced functionality.
Ideally, this should be tied in on a feature level - so I register both foo.js and bar.js to provide for feature A and in my template I just indicate I want all the static content for A.
You can follow the django admin framework approach. In your base template have an extra section for style and javascript. Based on some condition you can insert the new files.
For Example:
Define these two blocks in your base template
{% block extracss %}{% endblock %}
{% block extrajs %}{% endblock %}
If you want to add a js or css based on some condition, you can add a check inside
{% block extracss %}
{% if new_app_installed %}
# Insert your CSS
{% else %}
# Default
{% endif %}
{% endblock %}
You can also check if your plugin app is installed and pass this context variable from view to template.
from django.conf import settings
if "new_app" in settings.INSTALLED_APPS:
is_new_app_installed = True

Django Template inheritance: how many levels and what page to render

I would like to have some advice in constructing django template levels.
Reading the docs, I do not understand how to create a template hierarchy structure with more than 2 levels.
For example, I would like to create 3 levels of inheritance:
base.html
└── base_level2.html
├── level2_level3_1.html
└── level2_level3_2.html
This is my code:
base.html
First level
{% block level2 %}{% endblock %}
base_level2.html
{% extends "base.html" %}
{% block level2 %}
Second level
{% block level3_1 %}{% endblock %}
{% block level3_2 %}{% endblock %}
{% endblock %}
level2_level3_1.html
{% extends "base_level2.html" %}
{% block level3_1 %}
Third level, part 1
{% endblock %}
level2_level3_2.html
{% extends "base_level2.html" %}
{% block level3_2 %}
Third level, part 2
{% endblock %}
views.py:
def myView(request):
return render_to_response('level2_level3_1.html', {}, context_instance=RequestContext(request))
In this way I can see the following on my browser:
First level
Second level
Third level, part 1
And this is logical to me because I call render_to response only on level2_level3_1.html.
Of course, if call level2_level3_2.html, I get the message Third level, part 2 but not the Third level, part1.
How to solve this? Is that a good approach? I've structured stuff in this way because my real templates are very big, a lot of lines of code, so I would like to keep some order.
Any advice will be appreciated.
It's hard to say if it's a good or bad idea or not without knowing the specific functionality of your templates, but my immediate reaction is that you're trying to over organize your templates. I think most people would urge you away from more than a 3-tier system because it makes it more difficult to make small changes in the website and more difficult to keep track of where things are. from the Zen of Python:
Flat is Better than Nested
The recommendation for a 3-tier system inTwo Scoops of Django goes like this:
Each app has a base_<app_name>.html template. App-level base templates share a common parent, base.html.
Templates within apps share a common parent base_<app_name>.html template.
Any template at the same level as base.html inherits base.html
and for your naming schema, it might look like this:
| Templates/
|--base.html
|--someothertemplate.html # extends base.html
|--level2/
|----base_level2.html # extends base.html
|----level2_1.html # extends base_level2.html
|----level2_2.html # extends base_level3.html
EDIT: and there's no real reason for this:
Second level
{% block level3_1 %}{% endblock %}
{% block level3_2 %}{% endblock %}
where each block refers to the content of one template. you can simplify that to one block like
{% block level3 %}{% endblock level3%}
and then in each of the level3 templates, rename the blocks accordingly
Probably not the best way of doing it but you might user include https://docs.djangoproject.com/en/dev/ref/templates/builtins/#include
something like this for base_level2.html
{% extends "base.html" %}
{% block level2 %}
Second level
{% include "level2_level3_1.html" %}
{% include "level2_level3_2.html" %}
{% endblock %}
i've not tested this, so not sure it works.
and btw:
The include tag should be considered as an implementation of “render this subtemplate and include the HTML”, not as “parse this subtemplate and include its contents as if it were part of the parent”. This means that there is no shared state between included templates – each include is a completely independent rendering process.

How to create a custom Django template tag working outside of a block?

In my project, I need to treat CSS requirements differently depending on several parameters. Thus, I need an additional level of abstraction compared to available static management systems.
In my templates, I would like to be able to register CSS (and JS) requirements with a template tag which would look like {% register_css 'myfile.css' %}. This approach works like a charm.
However, there is still one problem with this approach : the tag works perfectly when inserted in a block, but never gets called when inserted on top of a child template. The tag definition is:
#register.simple_tag(takes_context = True)
def register_css(context, *args):
context['static_registry'].register_css(streamlet)
return ''
This is my test template:
{% extends main_skelton %}
{% load static_registry %}
{% register_css 'base' %}
{% block title %}Welcome{% endblock %}
{% block content %}
{% register_css 'home' %}
<p>Some content here</p>
{% endblock %}
In that template, the 'home' css gets registered, but not the 'base' one. How may I make both work?
Thanks!
Include an empty {% block init %} in your base template, then override that block in the child templates to register files - {% block init %}{{ block.super }} {% register_css 'foo %}{% endblock %}
The underlying issue is that in a child template, only blocks that match something in the parent template will get rendered. AFAIK there's no easy way around that, but using a dummy block works just fine.

Django admin: adding pagination links in list of objects to top

Is it possible to have the pagination links that appear at the bottom of a list of objects in Django's admin interface at the top as well?
Can this be done without changing the admin templates? I suspect not, given the lack of a ModelAdmin option, but thought I'd see if anyone had done this before I dug into the template code.
I really, really don't want to have to copy and paste change_list.html into a new file, just so I can add a pagination line - that'll make changing Django versions painful, since I'll have to check if anything's changed in that file, and re-apply my change.
Do not copy change_list.html, instead create a new template that extends it:
{% extends "admin/change_list.html" %}
{% block result_list %}
{% block pagination %} {{ block.super }} {% endblock %} <!-- pagination -->
{{ block.super }} <!-- rest of results list -->
{% endblock %}
Then pass the new template's name to ModelAdmin in change_list_template attribute - doc here.
The source code implementing the django admin template for change_list.html has a content block so if you create a file change_list.html under 'admin' folder in your templates directory and add this:
{% extends "admin/change_list.html" %}
{# added pagination to top as well as bottom #}
{% block content %}{% pagination cl %}{{ block.super }}{% endblock %}
it should do the trick!