Answers in other questions leave impression that this is in fact very easy:
django-allauth configuration doubts
overriding default templates of django-allauth
However, I can't get it to work at all.
From example app settings I can see that django-allauth supposedly expects it's templates to be in account, openid and socialaccount directories. But when I put template at TEMPLATE_DIR/account/signup.html it doesn't get loaded, signup view displays template bundled with django-allauth. What do I miss?
I eventually resorted to loading my app before django-allauth. In settings.py:
INSTALLED_APPS = (
...
'myapp',
'allauth',
'allauth.account'
)
This solution goes against what's presented in example app, but I was not able to solve it in other way.
To this day--- we're now on Django-1.10.5--- the django-allauth docs remain most unhelpful on this score. It does seem to be that Django looks in the templates directory of the first app listed, the setting of DIRS in TEMPLATES in settings.py notwithstanding. I'm providing an answer only to help you implement Adam Starrh's answer, to help with the reverse urls (I got errors until I took care of those).
In your urls.py file put:
from allauth.account.views import SignupView, LoginView, PasswordResetView
class MySignupView(SignupView):
template_name = 'signup.html'
class MyLoginView(LoginView):
template_name = 'login.html'
class MyPasswordResetView(PasswordResetView):
template_name = 'password_reset.html'
urlpatterns = [
url(r'^accounts/login', MyLoginView.as_view(), name='account_login'),
url(r'^accounts/signup', MySignupView.as_view(), name='account_signup'),
url(r'^accounts/password_reset', MyPasswordResetView.as_view(), name='account_reset_password'),
]
Presently the views.py file is here, so you can extend the above to other templates.
I must add that you still need in TEMPLATES, something like:
'DIRS': [
os.path.join(PROJECT_ROOT, 'templates', 'bootstrap', 'allauth', 'account'),
],
And in this example that would be if your templates are in /templates/bootstrap/allauth/account, which they are in my case. And:
PROJECT_ROOT = os.path.normpath(os.path.dirname(os.path.abspath(__file__)))
EDIT... THE PROPER WAY:
OK, the above works, to a point, and it's good that it directly sets the template to what you want. But as soon as you include social apps you'll start to get reverse url errors such as for dropbox_login, for which you have not provided a named view.
After reading Burhan Khalid's comment on this other stackoverflow thread that the questioner found, I eventually found that the following works:
'DIRS': [
os.path.join(PROJECT_ROOT, 'templates', 'example'),
]
And this yields /home/mike/example/example/templates/example on the development server in my case, as I am running the example app from git clone git://github.com/pennersr/django-allauth.git.
Into that dir of DIRS I copied the entire subdirectories account and socialaccount from the provided sample bootstrap templates. This is utterly contrary to the directory structure of example as it comes from github and to notes in the settings.py file of example.
And you leave urls.py just as in the example app, with simply:
url(r'^accounts/', include('allauth.urls')),
Adding a template directory for allauth in template dirs will do the trick. In Django 1.8 his can be done by editing template dir settingsTEMPLATES as follows.
TEMPLATES = [
...
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'templates', 'allauth'),
],
]
I think below code will work on other versions of django
TEMPLATE_DIRS = [
os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'templates', 'allauth'),
]
In your views:
from allauth.account.views import SignupView, LoginView
class MySignupView(SignupView):
template_name = 'my_signup.html'
class MyLoginView(LoginView):
template_name = 'my_login.html'
For me only one solution works:
first make TEMPLATE_LOADERS to load filesystem.Loader
TEMPLATE_LOADERS = [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
]
second - make TEMPLATE_DIRS with path where you copied templates from allauth. Make sure you copied full folder hierarchy from templates folder of allauth app.
TEMPLATE_DIRS = [
os.path.join(BASE_DIR, 'cms', 'templates', 'allauth'),
]
in this example a made path to my app, named cms because this is the main app of my project
after you could start to edit base.html template
I found a better way to do this but forgot. All Auth allows you to do this very easy but and low on documentation. Here is my next easiest solution, until I rediscover the vaster way. #lol
The code creates a custom login page but the pattern is simple and easy to replicate. You can put all this code in urls.py, or not:
from allauth.account.views import LoginView
class Lvx(LoginView):
# Login View eXtended
# beware ordering and collisions on paths
template_name = "components/login.html"
# don't forget to create the login page, see All Auth docs
# for use. /components is in your app templates path
login = Lvx.as_view()
urlpatterns = [
url(r'^accounts/login/$', login), # usually up top
...
]
There is also a setting you can use to point to a custom page, will edit this at some point. Feedback welcome.
As per the documentation provided here, it is possible to override the templates by replicating the directory structure inside the template base location of your project. For instance, by just creating the account/logout.html , I was able to override the logout.html file provided by allauth. The settings.py in my case is stated here
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
}
]
In django v2.0. I use this method and its works. By following the django book, [https://djangobook.com/mdj2-django-templates/] .
The important way is to use [os.path.join(BASE_DIR, 'name_of_your_file/templates/allauth')] instead of using 'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'templates', 'allauth')],
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'name_of_your_file/templates/allauth')],
'APP_DIRS': True,
This is my first time post at stackoverflow yah,i find this solution long time and finally its work so i share it, hope can help someone.
It's quite easy once you know Django's template look up order and you configure the TEMPLATE =[] properly as per your need. There's no need to play with views or Python code if it's just about overriding allauth's templates.
Let's understand the Django's template look up order at first, just a little. Django's template lookup order is as follows, all of these are configured inside TEMPLATE =[]in project's settings.py.
I. 'Loader': Give you the option to use Template Loaders which are responsible for locating templates, loading them, and returning Template objects. General implementations don't use it much. If you haven't configured a template loader then one of the following two option would decide which template is used by your view.
II. 'DIRS': Here you get the option to explicitly tell Django where to search for templates, in order, up to down.
III. 'APP_DIRS': If this field is set to true then Django looks for your template in your apps' dir. To correctly use this option you need to organize your templates as follows:
root_dir
app1_dir
templates
your_template.html
app2_dir
templates
your_template.html
You must name your templates dir as "templates" and you must put your templates in that dir only for this to work
Third option is little weird though, if a template in your app's view isn't found in corresponding app's template dir Django will go through template dir of other apps to find it.
It works well if templates are organized properly and naming convention of templates is standardized, so that when a template isn't found in local app's dir, that template shouldn't be erroneously found in other app's dir. Well, you may have some scenarios where you would want it to work that way.
Now, to the point answer to your question:
Allauth by default uses the templates from:
Python installed directory or virtual env --> *Lib --> site-packages --> allauth --> templates*
You would usually want to override all the allauth's templates as they are very basic and you would want to beautify/modify them all, following are the steps which would enable you to override them all, if you don't wish to override all of them do as follows, but just don't change the HTML for that template, simple!
Suppose your project structure is as follows:
projectdir
app1_dir
app2_dir
projectname_dir
Copy the templates dir from Python installed directory or virtual env --> Lib --> site-packages --> allauth --> templates to a dir of your choice, suppose you chose to keep it in app1_dir (you may chose any dir, makes no difference, but you should choose an appropriate one as per your requirements), then create a dir in app1_dir named 'allauth' (you could name it anything you like), then paste the copied allauth's templates dir in this dir, so now your project structure would look as follows:
projectdir
app1_dir
allauth
templates
account
openid
socialaccount
base.html
app2_dir
projectname_dir
Change your TEMPLATES = [] in project settings as follows:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'allauth', 'templates'),
],
'APP_DIRS': True,
},
]
Here BASE_DIR is projectdir (root dir)
Basically you may keep the copied template dir from allauth dir in any project's dir of your choice, but you must enusre that you provided the correct path here:
'DIRS': [os.path.join(BASE_DIR, 'allauth', 'templates')
If it doesn't work then, set 'APP_DIRS': False, then you would see a debug message from Django and it wouldn't use app dir (allauth dir in site-packages). And then looking at that error you may figure out what's wrong with your config.
Related
I am using Django honeypot (https://github.com/jamesturk/django-honeypot) and was wondering how to customize the honeypot_error.html page (https://github.com/jamesturk/django-honeypot/blob/master/honeypot/templates/honeypot/honeypot_error.html), which is executed when honeypot detection gets tripped. Thanks!!
if you had honeypot_error.html with the same structured path
templates/honeypot/honeypot_error.html in your project it will take your page as default. (see the key point to note: here )
example:
package x define a template named toto.html in templates/myapp/toto.html
in your application, add a customized toto.html in templates/myapp/toto.html
when calling
python manage.py collectstatic
it will get your template and not the one provided by default by myapp
I can't comment on MSR974's answer so:
From Django's documentation on overriding templates:
from pathlib import Path
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
INSTALLED_APPS = [
...,
'blog',
...,
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
...
},
]
Notice: "If you have app and project templates directories that both contain overrides, the default Django template loader will try to load the template from the project-level directory first. In other words, DIRS is searched before APP_DIRS."
As you read through the examples, keep in mind the distinction between APP and PROJECT templates and make sure you've configured your SETTINGS according to the chosen strategy.
I am currently working through some tutorials to enhance my knowledge of Django. In doing so, I decided to use to most recent version of Django. I have been able to overcome most of the divergences between my code and that of the tutorial except for one - static files are not being served. Now, I am not fully sure that the difference is strictly due to the Django version. Here is what is going on.
I have the following project structure:
settings.py
STATIC_URL = '/static/'
STATIC_FILES = (
os.path.join(BASE_DIR, "static"),
)
STATIC_ROOT = os.path.join (os.path.dirname(BASE_DIR), "staticfiles", "static")
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',
],
},
},
]
What is interesting is that with this configuration, the project is able to find templates successfully. However, as mentioned above, it cannot find the static files. Why is that?
Also, this tutorial sets up an unusual configuration in that the static and templates directories are located inside the main app's directory, whereas I typically have them one level higher, i.e., in the project root's directory. Could this be a part of the problem? What in the settings of this particular project makes Django look for files one directory lower? The settings seem the same as those of other project I had done. However, those project contained the static and templates directories in the project's root directory.
Any help and clarification is appreciated.
Edit:
urls.py
from django.contrib import admin
from django.urls import path
from .views import home
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', home, name='home')
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
try replacing this:
STATIC_ROOT = os.path.join (os.path.dirname(BASE_DIR), "staticfiles", "static")
with
STATIC_ROOT = os.path.join (os.path.dirname(BASE_DIR), "static")
Also provide the status of files (like 404 messages)
STATIC_FILES doesn't mean anything to Django, as far as I know, although maybe you are using it for another purpose.
The way you had STATIC_ROOT defined it was pointing to a non-existent directory.
There is a good reference in StackOverflow here
To serve static files you need to add the following configuration in urls.py as:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Next, I believe it is a good practice to put static and templates within their own apps, this is useful if you want to make that app plug-able any near future.
Or it is also a good practice to gather all static files in project level directory and add the following in settings to identify it.
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
edit: I just see the updated question. Try adding this:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', home, name='home')
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
This says, as long as we are in debug mode serve the static files.
try this:
STATIC_ROOT = os.path.join (BASE_DIR, "taskbuster", "static")
I was able to solve the issue by changing the settings to the following:
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
STATIC_ROOT = os.path.join (os.path.dirname(BASE_DIR), "static")
Furthermore, it was helpful to read the following documentation when trying to understand how to fix it
https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-STATICFILES_FINDERS
Particularly, this explained clearly what Django did:
The default will find files stored in the STATICFILES_DIRS setting
(using django.contrib.staticfiles.finders.FileSystemFinder) and in a
static subdirectory of each app (using
django.contrib.staticfiles.finders.AppDirectoriesFinder). If multiple
files with the same name are present, the first file that is found
will be used.
This is my current assets.py file:
from django_assets import Bundle, register
sass = Bundle(
'build/main.sass',
filters='sass',
output='css/main.css'
)
register('sass', sass)
Now I run into an issue with it saying Another bundle is already registered as "sass", but not seeing how to unregister it.
At any rate, I change register('sass', sass) to register('sass_all', sass) to get past the error. When I go to compile it is looking in my scripts directory where I keep manage.py. In settings.py I add:
ASSETS_ROOT = [
'static',
]
Which just has look in scripts/static which doesn't exist.
Tried:
# This is already in settings.py
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# Added new line
ASSETS_ROOT = [
STATICFILES_DIRS,
]
It generates a couple errors: KeyError: 'directory', OSError: The environment has no "directory" configured, and AttributeError: 'list' object has no attribute 'startswith'. Really it is just one error that directory isn't defined, I think.
Read through environment documentation which is vague given my skill level. In assets.py adding Environment to import just says Could not import in Environment. Adding Environment.directory('static') results in Environment is not defined. Just directory('static') also results in directory is not defined. env = Environment() same thing. Tried adding directory='/static' to sass = Bundle(...) which just says TypeError: got unexpected keyword argument 'directory'.
Anyway, spent a few hours on it and stuck again. Documentation seems to indicate directory settings should go in assets.py and not settings.py, whereas ASSETS_ROOT should be going in settings.py.
Thanks again in advance!
~/portal-client
project_dir
apps
account
templates
account
login.html
forms.py
urls.py
views.py
home
templates
home
home.html
urls.py
views.py
results
assets.py
settings.py
urls.py
scripts
manage.py
static
build
main.js
main.sass
css
app.css
main.css
js
app.js
main.js
media
templates
base.html
footer.html
title.html
Continuation from this question: Trouble adding Django-Assets / Webassets directory to look for assets.py files
A quick point to note:
# This is already in settings.py
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# After this line STATICFILES_DIRS is `[ 'BASE_DIR/static' ]`
# Added new line
ASSETS_ROOT = [
STATICFILES_DIRS,
]
# After this line, ASSETS_ROOT is `[ [ 'BASE_DIR/static' ] ]`
# i.e., an array of arrays
# I think you actually wanted:
ASSETS_ROOT = STATICFILES_DIRS[0]
# - or more explicitly -
ASSETS_ROOT = os.path.normpath(os.path.join(BASE_DIR, 'static'))
That said many of these issues look like they are being caused by a fairly non-standard django structure (i.e., that your manage.py is in the scripts directory rather than in BASE_DIR).
I'm working on an Open Source Django app and created some design for it. Now a customer wants to use it's own, copyrighted, design. After reading the Django docs I created a separate, private, GIT repository that I want to use for the new design. I got it almost working by adding 2 items to the settings; an extra entry to look for templates in a folder "funder_custom_templates" and an extra entry to look for static files in the same location. This is how I configured TEMPLATES and STATICFILES_DIR:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(PROJECT_DIR, '..', '..', 'funder_custom_templates'),
os.path.join(PROJECT_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',
'fundraiser.context_processors.cart',
],
},
},
]
STATICFILES_DIRS = [
os.path.join(PROJECT_DIR, '..', '..', 'funder_custom_templates','static'),
os.path.join(PROJECT_DIR, 'static'),
]
This works for overriding the base design located in the PROJECT_DIR/templates/base.html, when I create funder_customer_templates/base.html and for all the static files as expected. But I also want to override app specific template files like blog/templates/blog/blog_index_page.html
I tried to put these files in the root of funder_custom_templates and I tried to mimic the app folders structure in funder_custom_templates but that doesn't load the app specific templates. Is there a way to solve this?
Example project files, with the folder structure, located at: https://github.com/acidjunk/funder/tree/develop/
Since you are using the app_directories.Loader class to load templates (specified by setting 'APP_DIRS': True,), then for app specfic templates Django will iterate over your INSTALLED_APPS setting looking for a specific template file. The important thing here is that it does so in order.
So if you want to override blog/templates/blog/blog_index_page.html then you will need to have a custom_blog/templates/blog/blog_index_page.html inside an application that comes before blog.
I recommend wrapping up all custom static resources in their own django application and python package. This way you can simply install the package from its private repo and add it to the list of installed apps to override any static content and templates.
See Django's docs for more details on template loading: https://docs.djangoproject.com/en/1.9/ref/templates/api/#django.template.loaders.app_directories.Loader
I am trying to set up a new blog. I want to keep all my project templates folder in the same folder as where my settings.py is. To do this I did the following...
[...]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "templates/")],
'APP_DIRS': False,
'OPTIONS': {
'context_processors': [
[...]
But now, my admin panel layout doesn't work. How can I circumvent the above solution when using the admin panel? I get the error
Exception Type: TemplateDoesNotExist
Exception Value: admin/login.html
By disabling APP_DIRS you're forcing Django to look for your templates in the templates folder of your basedir regardless of where the app specifies them. This will break any plugins and also prevents you from namespacing templates. Its generally a bad idea.
DIRS is a list, so you can specify multiple locations if desperately want to hold the templates in a different locationand maintain access to teh admin