128đź‘Ť
Update:
Read the Docs for your version of Django, e.g. the latest version or old LTS versions: 3.2, 2.2, 1.11
Original answer from 2011:
I had the same issue about a year and a half ago and I found a nice template loader on djangosnippets.org that makes this easy. It allows you to extend a template in a specific app, giving you the ability to create your own admin/index.html that extends the admin/index.html template from the admin app. Like this:
{% extends "admin:admin/index.html" %}
{% block sidebar %}
{{block.super}}
<div>
<h1>Extra links</h1>
<a href="/admin/extra/">My extra link</a>
</div>
{% endblock %}
I’ve given a full example on how to use this template loader in a blog post on my website.
86đź‘Ť
As for Django 1.8 being the current release, there is no need to symlink, copy the admin/templates to your project folder, or install middlewares as suggested by the answers above. Here is what to do:
-
create the following tree structure(recommended by the official documentation)
your_project |-- your_project/ |-- myapp/ |-- templates/ |-- admin/ |-- myapp/ |-- change_form.html <- do not misspell this
Note: The location of this file is not important. You can put it inside your app and it will still work. As long as its location can be discovered by django. What’s more important is the name of the HTML file has to be the same as the original HTML file name provided by django.
-
Add this template path to your settings.py:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], # <- add this line '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', ], }, }, ]
-
Identify the name and block you want to override. This is done by looking into django’s admin/templates directory. I am using virtualenv, so for me, the path is here:
~/.virtualenvs/edge/lib/python2.7/site-packages/django/contrib/admin/templates/admin
In this example, I want to modify the add new user form. The template responsiblve for this view is change_form.html. Open up the change_form.html and find the {% block %} that you want to extend.
-
In your change_form.html, write somethings like this:
{% extends "admin/change_form.html" %} {% block field_sets %} {# your modification here #} {% endblock %}
-
Load up your page and you should see the changes
- [Django]-Error: "dictionary update sequence element #0 has length 1; 2 is required" on Django 1.4
- [Django]-How to perform OR condition in django queryset?
- [Django]-Celery : Execute task after a specific time gap
66đź‘Ť
if you need to overwrite the admin/index.html
, you can set the index_template parameter of the AdminSite
.
e.g.
# urls.py
...
from django.contrib import admin
admin.site.index_template = 'admin/my_custom_index.html'
admin.autodiscover()
and place your template in <appname>/templates/admin/my_custom_index.html
- [Django]-Substring in a django template?
- [Django]-PHP Frameworks (CodeIgniter, Yii, CakePHP) vs. Django
- [Django]-How to iterate through dictionary in a dictionary in django template?
24đź‘Ť
With django
1.5 (at least) you can define the template you want to use for a particular modeladmin
see https://docs.djangoproject.com/en/1.5/ref/contrib/admin/#custom-template-options
You can do something like
class Myadmin(admin.ModelAdmin):
change_form_template = 'change_form.htm'
With change_form.html
being a simple html template extending admin/change_form.html
(or not if you want to do it from scratch)
- [Django]-Django: Safely Remove Old Migrations?
- [Django]-Login Page by using django forms
- [Django]-How do I install psycopg2 for Python 3.x?
12đź‘Ť
I couldn’t find a single answer or a section in the official Django docs that had all the information I needed to override/extend the default admin templates, so I’m writing this answer as a complete guide, hoping that it would be helpful for others in the future.
Assuming the standard Django project structure:
mysite-container/ # project container directory
manage.py
mysite/ # project package
__init__.py
admin.py
apps.py
settings.py
urls.py
wsgi.py
app1/
app2/
...
static/
templates/
Here’s what you need to do:
-
In
mysite/admin.py
, create a sub-class ofAdminSite
:from django.contrib.admin import AdminSite class CustomAdminSite(AdminSite): # set values for `site_header`, `site_title`, `index_title` etc. site_header = 'Custom Admin Site' ... # extend / override admin views, such as `index()` def index(self, request, extra_context=None): extra_context = extra_context or {} # do whatever you want to do and save the values in `extra_context` extra_context['world'] = 'Earth' return super(CustomAdminSite, self).index(request, extra_context) custom_admin_site = CustomAdminSite()
Make sure to import
custom_admin_site
in theadmin.py
of your apps and register your models on it to display them on your customized admin site (if you want to). -
In
mysite/apps.py
, create a sub-class ofAdminConfig
and setdefault_site
toadmin.CustomAdminSite
from the previous step:from django.contrib.admin.apps import AdminConfig class CustomAdminConfig(AdminConfig): default_site = 'admin.CustomAdminSite'
-
In
mysite/settings.py
, replacedjango.admin.site
inINSTALLED_APPS
withapps.CustomAdminConfig
(your custom admin app config from the previous step). -
In
mysite/urls.py
, replaceadmin.site.urls
from the admin URL tocustom_admin_site.urls
from .admin import custom_admin_site urlpatterns = [ ... path('admin/', custom_admin_site.urls), # for Django 1.x versions: url(r'^admin/', include(custom_admin_site.urls)), ... ]
-
Create the template you want to modify in your
templates
directory, maintaining the default Django admin templates directory structure as specified in the docs. For example, if you were modifyingadmin/index.html
, create the filetemplates/admin/index.html
.All of the existing templates can be modified this way, and their names and structures can be found in Django’s source code.
-
Now you can either override the template by writing it from scratch or extend it and then override/extend specific blocks.
For example, if you wanted to keep everything as-is but wanted to override the
content
block (which on the index page lists the apps and their models that you registered), add the following totemplates/admin/index.html
:{% extends 'admin/index.html' %} {% block content %} <h1> Hello, {{ world }}! </h1> {% endblock %}
To preserve the original contents of a block, add
{{ block.super }}
wherever you want the original contents to be displayed:{% extends 'admin/index.html' %} {% block content %} <h1> Hello, {{ world }}! </h1> {{ block.super }} {% endblock %}
You can also add custom styles and scripts by modifying the
extrastyle
andextrahead
blocks.
- [Django]-How do you Serialize the User model in Django Rest Framework
- [Django]-Using JSON in django template
- [Django]-How to go from django image field to PIL image and back?
10đź‘Ť
Chengs’s answer is correct, howewer according to the admin docs not every admin template can be overwritten this way:
https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates
Templates which may be overridden per app or model
Not every template in contrib/admin/templates/admin may be overridden
per app or per model. The following can:app_index.html change_form.html change_list.html delete_confirmation.html object_history.html
For those templates that cannot be overridden in this way, you may
still override them for your entire project. Just place the new
version in your templates/admin directory. This is particularly useful
to create custom 404 and 500 pages
I had to overwrite the login.html of the admin and therefore had to put the overwritten template in this folder structure:
your_project
|-- your_project/
|-- myapp/
|-- templates/
|-- admin/
|-- login.html <- do not misspell this
(without the myapp subfolder in the admin)
I do not have enough repution for commenting on Cheng’s post this is why I had to write this as new answer.
- [Django]-Using JSON in django template
- [Django]-How do I use an UpdateView to update a Django Model?
- [Django]-How do I match the question mark character in a Django URL?
6đź‘Ť
The best way to do it is to put the Django admin templates inside your project. So your templates would be in templates/admin
while the stock Django admin templates would be in say template/django_admin
. Then, you can do something like the following:
templates/admin/change_form.html
{% extends 'django_admin/change_form.html' %}
Your stuff here
If you’re worried about keeping the stock templates up to date, you can include them with svn externals or similar.
- [Django]-Django South – table already exists
- [Django]-Choose test database?
- [Django]-How to mix queryset results?
4đź‘Ť
for app index add this line to somewhere common py file like url.py
admin.site.index_template = 'admin/custom_index.html'
for app module index : add this line to admin.py
admin.AdminSite.app_index_template = "servers/servers-home.html"
for change list : add this line to admin class:
change_list_template = "servers/servers_changelist.html"
for app module form template : add this line to your admin class
change_form_template = "servers/server_changeform.html"
etc. and find other in same admin’s module classes
- [Django]-Django – how to visualize signals and save overrides?
- [Django]-Convert Django Model object to dict with all of the fields intact
- [Django]-Filter Queryset on empty ImageField
3đź‘Ť
You can override django admin templates in several ways.
For example, there is django-project
as shown below:
django-project
|-core
| â””-settings.py
|-app1
| |-models.py
| â””-admin.py
|-app2
â””-templates
Then, BASE_DIR / 'templates'
is set to DIRS
in TEMPLATES
in settings.py
so that templates
folder is recognized as shown below:
# "core/settings.py"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BASE_DIR / 'templates', # Here
],
'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',
],
},
},
]
And, there are Food
and Drink
models in app1/models.py
as shown below:
# "app1/models.py"
class Food(models.Model):
name = models.CharField(max_length=20)
class Drink(models.Model):
name = models.CharField(max_length=20)
And, there are Food
and Drink
admins in app1/admin.py
as shown below:
# "app1/admin.py"
@admin.register(Food)
class FoodAdmin(admin.ModelAdmin):
pass
@admin.register(Drink)
class DrinkAdmin(admin.ModelAdmin):
pass
Now, you can override one of the django admin templates change_form.html in templates/admin/
, templates/admin/app1/
and templates/admin/app1/food/
as shown below. *You can copy django admin templates from django/contrib/admin/templates/admin/
in your virtual environment and some django admin templates cannot be overridden in templates/admin/app1/
or templates/admin/app1/food/
but these django admin templates can be overridden all in templates/admin/
, templates/admin/app1/
and templates/admin/app1/food/
and you can see my answer explaining which django admin templates can be overridden in which directories.
change_form.html
in templates/admin/
below can automatically apply to all admins in all apps. *The lowercase folder name admin
works properly:
django-project
|-core
| â””-settings.py
|-app1
| |-models.py
| â””-admin.py
|-app2
â””-templates
â””-admin
â””-change_form.html # Here
change_form.html
in templates/admin/app1/
below can automatically apply to all admins in app1
. *The lowercase folder name app1
works properly:
django-project
|-core
| â””-settings.py
|-app1
| |-models.py
| â””-admin.py
|-app2
â””-templates
â””-admin
|-app1
| â””-change_form.html # Here
â””-app2
change_form.html
in templates/admin/app1/food/
below can automatically apply to food
admin in app1
. *The lowercase folder name food
works properly:
django-project
|-core
| â””-settings.py
|-app1
| |-models.py
| â””-admin.py
|-app2
â””-templates
â””-admin
|-app1
| |-food
| | â””-change_form.html # Here
| â””-drink
â””-app2
And now, you can rename change_form.html
to custom_change_form.html
but custom_change_form.html
in any folders cannot automatically apply to any admins in any apps. So, you need to manually apply custom_change_form.html
to any admins in any apps which you want to apply custom_change_form.html
to.
For custom_change_form.html
in templates/admin/
below:
django-project
|-core
| â””-settings.py
|-app1
| |-models.py
| â””-admin.py
|-app2
â””-templates
â””-admin
â””-custom_change_form.html # Here
Set admin/custom_change_form.html
to change_form_template in Food
and Drink
admins as shown below. *You can find more custom template options:
# "app1/admin.py"
@admin.register(Food)
class FoodAdmin(admin.ModelAdmin):
change_form_template = 'admin/custom_change_form.html'
@admin.register(Drink)
class DrinkAdmin(admin.ModelAdmin):
change_form_template = 'admin/custom_change_form.html'
For custom_change_form.html
in templates/admin/app1/
below:
django-project
|-core
| â””-settings.py
|-app1
| |-models.py
| â””-admin.py
|-app2
â””-templates
â””-admin
|-app1
| â””-custom_change_form.html # Here
â””-app2
Set admin/app1/custom_change_form.html
to change_form_template
in Food
and Drink
admins as shown below:
# "app1/admin.py"
@admin.register(Food)
class FoodAdmin(admin.ModelAdmin):
change_form_template = 'admin/app1/custom_change_form.html'
@admin.register(Drink)
class DrinkAdmin(admin.ModelAdmin):
change_form_template = 'admin/app1/custom_change_form.html'
For custom_change_form.html
in templates/admin/app1/food
below:
django-project
|-core
| â””-settings.py
|-app1
| |-models.py
| â””-admin.py
|-app2
â””-templates
â””-admin
|-app1
| |-food
| | â””-custom_change_form.html # Here
| â””-drink
â””-app2
Set admin/app1/food/custom_change_form.html
to change_form_template
in Food
and Drink
admins as shown below:
# "app1/admin.py"
@admin.register(Food)
class FoodAdmin(admin.ModelAdmin):
change_form_template = 'admin/app1/food/custom_change_form.html'
@admin.register(Drink)
class DrinkAdmin(admin.ModelAdmin):
change_form_template = 'admin/app1/food/custom_change_form.html'
- [Django]-How to check if ManyToMany field is not empty?
- [Django]-How can I call a custom Django manage.py command directly from a test driver?
- [Django]-Passing variable urlname to url tag in django template
1đź‘Ť
I agree with Chris Pratt. But I think it’s better to create the symlink to original Django folder where the admin templates place in:
ln -s /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/ templates/django_admin
and as you can see it depends on python version and the folder where the Django installed. So in future or on a production server you might need to change the path.
- [Django]-Checking for empty queryset in Django
- [Django]-How to format time in django-rest-framework's serializer?
- [Django]-Django custom field validator vs. clean
0đź‘Ť
This site had a simple solution that worked with my Django 1.7 configuration.
FIRST: Make a symlink named admin_src in your project’s template/ directory to your installed Django templates. For me on Dreamhost using a virtualenv, my “source” Django admin templates were in:
~/virtualenvs/mydomain/lib/python2.7/site-packages/django/contrib/admin/templates/admin
SECOND: Create an admin directory in templates/
So my project’s template/ directory now looked like this:
/templates/
admin
admin_src -> [to django source]
base.html
index.html
sitemap.xml
etc...
THIRD: In your new template/admin/ directory create a base.html file with this content:
{% extends "admin_src/base.html" %}
{% block extrahead %}
<link rel='shortcut icon' href='{{ STATIC_URL }}img/favicon-admin.ico' />
{% endblock %}
FOURTH: Add your admin favicon-admin.ico into your static root img folder.
Done. Easy.
- [Django]-How to get the domain name of my site within a Django template?
- [Django]-Where to put business logic in django
- [Django]-Table thumbnail_kvstore doesn't exist
-1đź‘Ť
You can use django-overextends, which provides circular template inheritance for Django.
It comes from the Mezzanine CMS, from where Stephen extracted it into a standalone Django extension.
More infos you find in “Overriding vs Extending Templates” (http:/mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates) inside the Mezzanine docs.
For deeper insides look at Stephens Blog “Circular Template Inheritance for Django” (http:/blog.jupo.org/2012/05/17/circular-template-inheritance-for-django).
And in Google Groups the discussion (https:/groups.google.com/forum/#!topic/mezzanine-users/sUydcf_IZkQ) which started the development of this feature.
Note:
I don’t have the reputation to add more than 2 links. But I think the links provide interesting background information. So I just left out a slash after “http(s):”. Maybe someone with better reputation can repair the links and remove this note.
- [Django]-Laravel's dd() equivalent in django
- [Django]-Is there a way to loop over two lists simultaneously in django?
- [Django]-Create custom buttons in admin change_form in Django