Two apps extend from the same base.html in Django - django

I have two apps. Both have different base.html templates that index.html extends from. The index.html is different though on each app.
But for some reason it only extends from the same app with base.html? How is this possible?
This is how it looks in both of my my index.html templates:
{% extends 'base.html' %}

How is your template/ directory structure set up? If an index.html template extends from base.html, Django will choose whatever base.html is in your root template directory.
Solution:
Either rename one of your base.html templates to something like base2.html and put it in templates/ alongside base1.html, or create new directories in templates/ to put the base.html files into.
For solution A, make sure you change {% extends base.html %} to {% extends base2.html %} in the appropriate index.html template.
For solution B, your base.html files would keep the same name, but be in different directories. So one is in say templates/base1/base.html and the other is in templates/base2/base.html. Your index.html files would extend like {% extends base1/base.html %} and {% extends base2/base.html %}. Note that all extension paths are relative to the root of your chosen template directory.
IMO solution B is better as it separates the code for each template base into different, explicitly named folders. Better organization/flexibility and less confusion for you in the future.

Related

Django admin: every app with different custom base_site.html

Hi I have been trying to customize my admin page and I have some application specific admin pages that require custom javascript and css. I would like to have different base_site.html within the template/admin/ of each app including the required javascript and css. The thing is that only the changes of the base_site.html of the first registered app (inside the settings.py file) are shown.
Is my approach of customizing base_site.html for each app correct? if yes, how can I get it to work?
How to include css and js only in some admin pages?
Thank you.
-app1
-templates
-admin
-base_site.html
-app2
-templates
-admin
-base_site.html
-app3
-templates
-admin
-base_site.html
-manage.py
If you just want to add some custom javascript and css to your admin you'd better use ModelAdmin asset definitions. See django docs for more. Something like this:
class ArticleAdmin(admin.ModelAdmin):
class Media:
css = {
"all": ("my_styles.css",)
}
js = ("my_code.js",)
As for base_site.html, you will not be able to override it for each application, it is general template not application specific template. But anyways, you could override/extend change_form.html and change_list.html templates, based on each application or even for each model. And tree should be as follows:
-app1
-templates
-admin
-app1
-change_form.html
-change_list.html
And if you use extension rather than overriding you may access header using extrahead and extrastyle blocks.
/app1/templates/admin/app1/change_form.html
{% extends "admin/change_form.html" %}
{% block extrahead %}
{{ block.super }}
... your code here ...
{% endblock %}

Django display list items based on URL

I'm trying to hide/show sections of my navigation depending on my active URL.
I have attempted to do this using the re.match() method, but jinja did not like this. This code is in an HTML include file for my side navigation and is as follows:
<ul>
{% if bool(re.match('^/url/path', request.get_full_path)) %}
<li><a href='link1'>Link1</a></li>
<li><a href='link1'>Link2</a></li>
<li><a href='link1'>Link3</a></li>
{% endif %}
</ul>
Thanks in advance.
You can create a custom filter and use it. Something like this maybe;
# nav_active.py
import re
from django.template import Library
from django.core.urlresolvers import reverse
register = Library()
#register.filter()
def nav_active(request_path, search_path):
# WRITE YOUR LOGIC
return search_path in request_path
Inside the template
{% load nav_active %}
{% if request_path|nav_active:"/search/path" %}
....
{% endif %}
Update as per your comment. From Django docs code layout section for custom template tags and filters:
The app should contain a templatetags directory, at the same level as models.py, views.py, etc. If this doesn’t already exist, create it - don’t forget the init.py file to ensure the directory is treated as a Python package.
So create a folder at same level as your view.py and name it templatetags. (Don't forget to add __init__.py inside). At the same level of that __init__.py add your nav_active.py and it should be ready to use. Like this:
yourapp/
__init__.py
models.py
views.py
templatetags/
__init__.py
nav_active.py

Django unable to distinguish between template directory when extending

I have two apps, consisting of adminApp and mobileApp. Both have their own template directory and totally seperated. Unfortunately django keeps looking in the wrong directory when i eg. use extend, it looks into the first template directory according to the order in INSTALLED_APPS:
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
INSTALLED_APPS = (
...
'adminApp',
'mobileApp',
...
)
My directory structure is:
adminApp/
templates/
base.html
mobileApp/
templates/
base.html
So basically what happens is that when i have a file such as mobileApp/templates/pages/index.html with a {% extends "base.html" %} it uses adminApp/templates/base.html instead of its own.
How can i avoid this and keep them separated?
Your apps don't follow the Django conventions for template directories. The app name should be repeated to avoid this issue:
adminApp/
templates/
adminApp/
base.html
mobileApp/
templates/
mobileApp/
base.html
You can then unambiguously specify which template you wish to extend:
{% extends "mobileApp/base.html" %}

Template Filter crashing

I have a template filter that I am loading in my template.
The template is in:
- userprofile/
- templatetags/
- __init__.py
- extras.py
Userprofile is in my installed apps and it seems to be importing extras correctly.
My template tag in extras.py is:
register = template.Library()
#register.filter
def minutes_seconds(seconds):
"""
Format a time in seconds in the MM:SS form.
"""
return '{:02}:{:02}'.format(int(seconds) / 60, int(seconds) % 60)
And in my django template I am doing:
{% extends 'base.html' %}
{% load extras %}
...
{{ items|minutes_seconds }}
But this blows up, and I get a TemplateSyntaxError: Invalid Filter. It seems to be a very low level error, because I can cause other errors in the template (for example, removing a {% for %} tag so it would otherwise raise an error), but it seems to be triggering this TempalteSyntaxError almost before the page is even rendered. What is going wrong here?
Check the dir "userprofile/templatetags/", are there compiled python files for init.py and extras.py?
If there are no compiled files in there then it means that templatetags dir is not being accessed by python. Make sure init.py file is there in that dir then restart the server and again check for .pyc files.

django include template from another app

While setting up my project and working to keep apps non-dependent, I've hit a snag. I'd like all of the templates from the different apps to have a consistent header and footer. Here's what I'm trying:
myproject/
base/
templates/
header.html
footer.html
app1/
templates/
my_app1_page.html -> want to include 'header.html'
and 'footer.html' from base app
Pretend there are many more apps that want to do this as well. Is this possible and/or the right way to do it?
As long as the apps are in INSTALLED_APPS and the template loader for apps dirs is enabled, you can include any template from another app, i.e.:
{% include "header.html" %}
... since your templates are located directly in the templates dir of your app.
Generally, in order to avoid name clashes it is better to use:
app1/
templates/
app1/
page1.html
page2.html
app2/
templates/
app2/
page1.html
page2.html
And {% include "app1/page1.html" %} or {% include "app2/page1.html" %} ...
But: for keeping a consistent look and feel, it is so much better to use template inheritance rather than inclusion. Template inheritance is one of the really good things of the Django template system, choose inheritance over inclusion whenever it makes sense (most of the time).
My recommendations:
Have a base template for your project ("base.html" is the default convention) with header and footer and a {%block content%} for your main content.
Have your other templates inherit form base.html {% extends "base.html" %} and override the content section
See another response to this question for links to the doc
While you can certainly do that by using the include tag and specifying absolute paths, the proper way to work in Django is by using Template inheritance.
If you start a project with "$ django-admin startproject project" a folder named "project-folder-name" i.e. project/ is created. After adding a few apps and adding the apps in the "settings.py" -> INSTALLED_APPS=[..., app1, app2] and creating a templates folder within the project/ I got structure like this:
project/
project/
templates/
base.html
app1/
templates/
app1/
page1.html
page2.html
app2/
templates/
app2/
page1.html
page2.html
in template app1/template/page1.html I wrote
{% extends 'base.html' %}
and the "TemplateDoesNotExist at /" Error message appeared.
Then I added another App named "core" and added base.html to the template folder (+edit INSTALLED_APPS in settings.py) and i got this structure now:
project/
project/
templates/ (unused)
base.html (not seen)
core/
templates/
base.html
app1/
templates/
app1/
page1.html
page2.html
[...]
Now the error message disappears and the base.html is found with templates/app1/page1.html:
{% extends 'base.html' %}
You can change the folder structure like this:
core/
templates/
core/
base.html
then you need to change the template app1/page1.html to
{% extends 'core/base.html' %}
as well.
As an alternative you can also add "your-project-name" in this explaination "project" into your settings file like this:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'project', # your project name main folder
'core',
'App1',
'App2',
]
And now django finds the project/templates/base.html as well. However I don't know if this solution is recommended.
project/
project/
templates/
base.html (now it is found)
P.S. Thanks (my upvotes aren't counted yet) and comment me if this answer was somehow clear and understandable