Whats the correct structure for Django templates? - django

I have a project in Django called: "my_site", and an app called "blog", I'm trying to render the "index.html" inside the path: my_site/blog/templates/blog/index.html. But keep getting this error:
Template-loader postmortem
Django tried loadi
ng these templates, in this order:
Using engine django:
django.template.loaders.filesystem.Loader: C:\Users\Ricardo Neto\Dev\Django_Projects\my_site\templates\index.html (Source does not exist)
django.template.loaders.app_directories.Loader: C:\Python310\lib\site-packages\django\contrib\admin\templates\index.html (Source does not exist)
django.template.loaders.app_directories.Loader: C:\Python310\lib\site-packages\django\contrib\auth\templates\index.html (Source does not exist)
django.template.loaders.app_directories.Loader: C:\Users\Ricardo Neto\Dev\Django_Projects\my_site\blog\templates\index.html (Source does not exist)
The view:
def index(request):
return render(request, 'index.html')
the urls.py:
urlpatterns = [
path('', views.index),
path('posts', views.show_all_posts),
path('posts/<slug:slug>', views.show_post)
]
If i move the index.html outside the blog folder, like in this example: my_site/blog/templates/index.html
the code runs and the index.html renders without problem, but i was taught that the correct structure is to create a folder inside templates with the same name of the app.
So could anyone please explain me the way i should structure my files?

rather than keeping it within the app. I prefer to keep it under the project file. my_site/templates/app_x/index.html
├───accounts
│
├───django_project
│
└───templates
├───accounts
└───registration
In settings.py file update the DIRS to the path of the templates folder. Generally, the templates folder is created and kept in the sample directory where manage.py.
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
If I open separate files under templates, I render them as folder_name/index.html, otherwise directly as index.html.

Django resolves templates relative to the "templates" directory located inside the app directory and chooses the first template across all apps whose name matches. For example, if you have two apps: blog and news both with templates named "index.html" in the "templates" directory, Django would not be able to choose correctly one of them. To make a distinction you can create a subfolder inside the "templates" directory named after the corresponding application: "blog/templates/blog/index.html" and "news/templates/news/index.html". And after that you can use those templates in the view functions like this: render(request, 'news/index.html') and render(request, 'blog/index.html').
You can read about this topic here, check the remark "Template namespacing": https://docs.djangoproject.com/en/4.0/intro/tutorial03/

Related

TemplateDoesNotExist error when extending an app template

I am having trouble setting up a template (under app directory) to extend a base.html that is in the root/templates/jinja2 directory
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [
os.path.join(BASE_DIR, 'templates/jinja2')
],
'APP_DIRS': True,
...
},
}
]
folder structure:
apps
|---app1
|---templates
|---jinja2
|---listing.html
|---templates
|---jinja2
|---base.html
listing.html
{% extends "base.html" %}
...
The error I am getting when I pull listing.html:
TemplateDoesNotExist at ...
base.html
Django tried loading these templates, in this order:
Using engine django:
django.template.loaders.app_directories.Loader: /webapps/pickup/env/lib/python3.7/site-packages/django/contrib/admin/templates/base.html (Source does not exist)
django.template.loaders.app_directories.Loader: /webapps/pickup/env/lib/python3.7/site-packages/django/contrib/auth/templates/base.html (Source does not exist)
django.template.loaders.app_directories.Loader: /webapps/pickup/src/apps/listing/templates/base.html (Source does not exist)
What is the right way to extend to a base template in the root template folder? I am using Django 3.0.5
Make your folder structure proper
apps
|---app1
|---templates
|---app1
|---listing.html
|---base.html
APP_DIRS means U can use templates folder in app what U've registered in settings.
To specify custom path U need to add NAME parameter.
Or just try to move listing.html in app1/templates/app1/

Template Does not Exist on IIS+Django

After the deployment process of my Django website on IIS i am getting an error like below,
TemplateDoesNotExist at /test/new_site/list/
Template-loader postmortem
Django tried loading these templates, in this order:
Using engine django:
django.template.loaders.app_directories.Loader: D:\workspace\One_Site_Project\env_one_site_37\lib\site-packages\django\contrib\admin\templates\test\new_site_list.html (Source does not exist)
django.template.loaders.app_directories.Loader: D:\workspace\One_Site_Project\env_one_site_37\lib\site-packages\django\contrib\auth\templates\test\new_site_list.html (Source does not exist)
django.template.loaders.app_directories.Loader: D:\workspace\One_Site_Project\env_one_site_37\lib\site-packages\rest_framework\templates\test\new_site_list.html (Source does not exist)
I don't know why IIS is searching my templates files in virtualenv directory.
My view rendering code is,
#method_decorator(csrf_exempt, name='dispatch')
class NewSiteListUpdate(View):
"""
This class is used to list all the new site activity, also update an activity
"""
def get(self, request, *args, **kwargs):
"""
List all the activity info or a particular activity info
:param request:
:param args:
:param kwargs:
:return:
"""
if request.user.is_staff:
self.data = ActivityInformation.objects.all()
self.radius = 11111
return render(request, 'test/new_site_list.html', {'data': self.data})
Below is my template settings in settings.py file,
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR + '/template/'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
# 'builtins': [
# 'src.huawei.templatetags.custom_tags'
# ],
'libraries':{
'custom_tags': 'templatetags.custom_tags',
},
},
},
]
Below is my project structure,
This is working fine in my local system. I tried to add the template folder in to the virtual directory also, but no use, still the same error is showing. I followed this tutorial in order to set up my application on IIS.
I am using python 3.7 and IIS 8.5
I spend my two days for solving this issue but i did not find any solution related to this.
Any help would be greatly appreciated. Thanks in Advance.
I think that you have to modify some part in your code
settings.py
try to change 'DIRS': [BASE_DIR + '/template/'], to 'DIRS'=[os.path.join(BASE_DIR, 'template'), ]
views.py
The path made by the render function will be : ../template/huawei/new_site_list.html but in your project structure your don't have a folder huawei. You must write : return render(request, 'test/new_site_list.html', {'data': self.data})

Upload custom templates in django

I want users to be able, to upload their custom html templates including css styling and png and jpeg images. These html files shall be retrievable through django. That means that they can see the resulting html content in form of a normal webpage. In order to be able to do that, I (seemingly, don't know a better approach yet) have to upload the html files in the template directory.
This is my current model:
class StylesheetFile(models.Model):
HTML = 'HTML'
CSS = 'CSS'
JPEG = 'JPEG'
PNG = 'PNG'
# Currently supported mimetypes
MIMETYPE_CHOICES = (
(HTML, 'text/html' ),
(CSS , 'text/css' ),
(JPEG, 'image/jpeg'),
(PNG , 'image/png' ),
)
mimetype = models.CharField(max_length=64, choices = MIMETYPE_CHOICES)
company = models.ForeignKey(Company)
file = models.FileField(upload_to=get_upload_path)
And this is the current function to determine the upload_path:
def get_upload_path(instance, filename):
if instance.mimetype == 'HTML':
return os.path.join(
settings.TEMPLATES[0]['DIRS'][1],
instance.company.name,
filename)
if instance.mimetype == 'CSS':
return os.path.join(
"custom_css",
instance.company.name,
filename)
if instance.mimetype == 'JPEG' or instance.mimetype == 'PNG':
return os.path.join(
"custom_img",
instance.company.name,
filename)
Template settings
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'/home/ubuntu/app/templates/',
'/home/ubuntu/app/custom_templates',
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
When I do this the css stylings, png and jpeg files are getting uploaded correctly, but the html files not. I receive following error:
The joined path (/home/ubuntu/app/custom_templates/FooCompany/factors.html) is located outside of the base path component (/home/ubuntu/app/static/media)
What can I do to prevent this error? Is there some best practice approach to my problem or do I have to go for some workaround like setting one of m y TEMPLATE_DIRS to /home/ubuntu/app/static/media/custom_templates. Maybe this is not even a workaround and legit practice.. I don't know really know.. Help is appreciated a lot!
You cannot use FileField to upload files outside of MEDIA_ROOT. That's an important security measure.
You could set TEMPLATE_DIRS to something inside MEDIA_ROOT and most likely this would work, but this makes my cringe really hard. That would essentially gave the users an ability to overwrite any template for any page on the site.
You don't have to save those templates as HTML files to use them as Django templates. You can save them in a database and render them directly from string:
from django.template import engines
from django.http import HttpResponse
# Get the template from database
template_from_db = YourCustomTemplateModel.objects.get(name='homepage')
template_string = template_from_db.content
# Create a django Template object
template = engines['django'].from_string(template_string)
# Render the template to a string
context = {'foo': 'bar'}
page_content = template.render(context=context)
# Send page to a the browser
return HttpResponse(page_content)
You should however think really hard about the security implications of doing this in general. Are you really comfortable with template creators being able to set arbitrary JavaScript on your domain (think cross-site scripting vulnerability)? What about calling arbitrary methods (or at least the ones not having any arguments) and accessing arbitrary arguments on objects you pass in the context dictionary?

Importing django.contrib.auth.urls does not play well with existing admin templates

I've been trying to follow documentation on using builtin Django templates to login/logout nonstaff users on a Django (1.9) site. In particular, I modified the urlconf by adding
url('^', include('django.contrib.auth.urls'))
which brings in /login and /logout endpoints and views with default template names preprogrammed.
The default template names for login and logout are registration/login.html and registration/logged_out.html. The first one doesn't exist anywhere, so I assumed I should create a templates/registration/ and create the login template, which I did. I thought the same thing should work for the logout, except it doesn't.
What actually happens is that the template resolves to django.contrib.admin.templates.registration.logged_out.html. This is pretty but stinks because the login link points to the admin login, which no nonstaff user will be able to use.
I really wish I could use the urlconf above, use the default template names, but write my own templates. Isn't this possible? The alternative seems to be repeating a bunch of stuff and that isn't very Pythonic.
I imagine it might involve modification of the TEMPLATES setting, or changing the orders of something else in the settings.
Whatever the solution is, I hope it does not interfere with the proper resolution of the admin templates (i.e. it would be bad if those started using my new templates.)
Requested details:
I created a login.html in (appname)/templates/registration/, and it works just fine when visiting the login url.
I created a logged_out.html in (appname)/templates/registration/ also, but discovered that when visiting the logout url, I got the admin site logged_out template (the one that says "Thanks for spending some quality time with the Web site today."
My templates setting:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'debug': True,
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
INSTALLED_APPS = (
'django.contrib.admin',
'app',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles'
)
Project structure (omitting what I guess is nonessential, and using some generic names.)
project/
app/
templates/
app/
registration/
login.html
logged_out.html
models.py
views.py
admin.py
gettingstarted/
static/
settings.py
urls.py
The structure may look a bit weird since it was adapted starting from the Heroku "Getting started with python" app.
Update
I finally struck upon the right search terms in the Django bug tracker and found that is a known issue. Disappointingly it's already three years old with no comment in the past two years. I guess I will just have to bite the bullet and define my own urls that use templates on a different path.
Django's template lookup is done top down by the order of INSTALLED_APPS. Meaning that if you want to override a template, the overriding template app should be listed above the overriden one in the admin.
In this case, project.app should be placed above django.contrib.admin so when creating /registration/logout.html it'll be loaded before the admin template.
In general, the recommended order of installed apps is: project -> 3rd party apps -> django builtins. It also affects static files finders.
Because of a bug in Django, overriding the registration/logged_out.html template overrides the admin "logged_out" template as well.
You can include the logout view specifically and specify a different "logged out" template or next_page (the view where it redirects after logout):
from django.contrib.auth import views as auth_views
urlpatterns = [
url(r'^logout/$', auth_views.logout, {'next_page': '/'}, name='logout'),
url('^', include('django.contrib.auth.urls')),
]
This will redirect to / after logout. It can also be a named url.
Or to change the logged_out template location use:
url(r'^logout/$', auth_views.logout, {'template_name': 'logged_out.html'}, name='logout'),
And then create logged_out.html in project/app/templates/.
I would use the first option if you want to redirect the user back to the home page after logout, and the 2nd if you want to display a "logged out" message.

Django: sorl-thumbnail and easy-thumbnail in same project

I'm working on and project that uses two separate modular Django apps. However, one app requires easy-thumbnails and the other requires sorl-thumbnails. Unfortunately, the two thumbnail libraries make use of the template tag syntax {% load thumbnail %}, so they clash and break when a template using them tries to render.
Are there any approaches to solve this type of clash? (For example, a template option does to the effect of {% load thumbnail as easy_thumbnail %}). Am I going to have to fork one of the apps and replace one of the thumbnail libraries with another? If so, which should I choose to go with?
Thank you for considering my question,
Joe
In Django 1.9, you can use the libraries option of DjangoTemplates to include a tag library under a specified name. In the example below, the thumbnail library from sorl.thumbnail is included under the name sorl_thumbnail.
Note: the templatetag itself is not changed within the template... ie. remains thumbnail
Usage:
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "foo", "templates")],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries': {
'sorl_thumbnail': 'sorl.thumbnail.templatetags.thumbnail',
},
},
},
]
your_template.html
{% load sorl_thumbnail %}
{% thumbnail mymodel.image "640x480" crop="center" as im %}
<img src="{{ im.url }}" width="{{im.width}}" height="{{im.height}}"/>
{% endthumbnail %}
Sure, just write your own stub easy_thumbnail wrapper...
Create a thumbnailtags package in one of your django apps...
...making sure it's got an empty __init__.py
In thumbnailtags/easy_thumbnail.py do something like:
from django.template import Library
from easy_thumbnails.templatetags import thumbnail
register = Library()
def easy_thumbnail(parser, token):
return thumbnail(parser, token)
register.tag(easy_thumbnail)
Use {% load easy_thumbnail %}
Note:
You might also be able to do 'import thumbnail as easy_thumbnail, and skip the def easy_thumbnail bit, tho I've not tried that.
This blog link shows how to handle this.
https://timmyomahony.com/blog/using-sorl-thumbnail-and-easy-thumbnails-same-template/
(previously
http://timmyomahony.com/blog/2012/10/22/using-sorl-thumbnail-and-easy-thumbnails-same-template/)
UPDATE 2015
I had to do the following modifications to Tom Christie's answer in order to get this to work:
create a templatetags package in one of you local apps. It is important to name it templatetags. See django docs for template tags.
... make sure it has an __init__.py, empty or not.
In templatetags/easy_thumbnail.py do this:
from django.template import Library
from easy_thumbnails.templatetags import thumbnail
register = Library()
def easy_thumbnail(parser, token):
return thumbnail.thumbnail(parser, token) # the important bit
register.tag(easy_thumbnail)
Use {% load easy_thumbnail %} or - load easy_thumbnail with pyjade