I am looking for the solution. I think a lot of different examples have confused me a little. I want to override the object-tools template in the Django admin.
I have one button on my model's tools:
I need one other same type of button "Upload file". This should redirect me to the another view which I want to design myself in the same admin base template (with just one upload file control).
[A]
Move "django.contrib.admin" in your INSTALLED_APPS to end of INSTALLED_APPS.
You can make template file
<your_app>/templates/admin/<your_app>/<your_model>/change_list.html
source code:
{% extends "admin/change_list.html" %}
{% block object-tools-items %}
<li>
<a href="<your-action-url>" class="addlink">
Upload file
</a>
</li>
{{ block.super }}
{% endblock %}
[B]
Add change_list_template into your ModelAdmin.
class MyModelAdmin(admin.ModelAdmin):
change_list_template = '<path-to-my-template>.html'
And write template like [A] source code.
It has become lot easier to accomplish what you're looking for since this question has been asked the first time.
The Django documentation has a section on how to override admin templates. To add a button to the changelist object tools, follow these steps:
Copy Django's version of the change_list_object_tools.html template file into your project's or app's template folder: templates/admin/<app>/<model>/change_list_object_tools.html.
You can obtain the file form your virtual env's site-packages folder:
cp $VIRTUAL_ENV/lib/python3.8/site-packages/django/contrib/admin/templates/admin/change_list_tools.html templates/admin/$APP/$MODEL/
Note that you might need to adjust the path to site-packages for your Python version.
Now open the template file. It will look liek this:
{% load i18n admin_urls %}
{% block object-tools-items %}
{% if has_add_permission %}
<li>
{% url cl.opts|admin_urlname:'add' as add_url %}
<a href="{% add_preserved_filters add_url is_popup to_field %}" class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
{% endif %}
{% endblock %}
Add the link to your custom view:
…
{% if has_add_permission %}
<li><a class="addlink" href="{% url 'upload-file' %}">Upload file</a></li>
<li>
…
That's it! If you didn't know: you can add custom views and URLs to a ModelAdmin using ModelAdmin.get_urls() (docs). To not have to hardcode your custom admin URLs, you can of course reverse them (docs).
You can try to use https://github.com/texastribune/django-object-actions.
This will allow you to add buttons with custom logic. Though, I'm not sure whether you'll be able to a buttom for your list screen, as I did it only for a model-edit page.
Related
As we known, there is an "Add" button in each model in django admin site. How can I change the name of it into like "Add Student" to make it customerized.
I have found the add button in the template
{% if has_add_permission %}
{% url cl.opts|admin_urlname:'add' as add_url %}
<el-button size="small" type="primary" icon="el-icon-plus" data-name="add_item"
url="{% add_preserved_filters add_url is_popup to_field %}">
{% trans 'Add' %}
</el-button>
{% endif %}
I change the "{% trans 'Add' %}" and the button's name can be changed, but all the models page Add button are changed. Is there any way to change it just for one model?
Not looking at your code is hard to give an exact answer but you can override any admin template by extending it.
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing-an-admin-template
Below is an example to extend change_form similarly you can do for any admin form - just find where this add button is and extend it.
{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
CUSTOM_CODE
{% endblock %}
There might be possibility to do via python code as well but need to see code for it
I'm building a website using django with a header on top of every page, which basically is a menu with a few links, constant throughout the pages.
However, depending on the page you're on I'd like to highlight the corresponding link on the menu by adding the class "active". To do so, I am currently doing as follow: each page has a full menu block that integrates within a general layout, which does NOT contain the menu. For exemple, page2 would look like this:
{% extends "layout.html" %}
{% block menu %}
<li>Home</li>
<li>page1</li>
<li class="active">page2</li>
<li>page3</li>
{% endblock %}
The problem is that, beside from that solution being not so pretty, every time I want to add a link to the header menu I have to modify each and every page I have. Since this is far from optimal, I was wondering if any of you would know about a better way of doing so.
Thanks in advance!
You can create a custom templatetag:
from django import template
from django.core.urlresolvers import reverse, NoReverseMatch, resolve
register = template.Library()
#register.simple_tag
def active(request, view_name):
url = resolve(request.path)
if url.view_name == view_name:
return 'active'
try:
uri = reverse(view_name)
except NoReverseMatch:
uri = view_name
if request.path.startswith(uri):
return 'active'
return ''
And use it in the template to recognize which page is loaded by URL
<li class="{% active request 'car_edit' %}">Edit</li>
If you have a "page" object at every view, you could compare a navigation item's slug to the object's slug
navigation.html
<ul>
{% for page in navigation %}
<li{% ifequal object.slug page.slug %} class="active"{% endifequal %}>
{{ page.title }}
</li>
{% endfor %}
</ul>
base.html
<html>
<head />
<body>
{% include "navigation.html" %}
{% block content %}
Welcome Earthling.
{% endblock %}
</body>
</html>
page.html
{% extends "base.html" %}
{% block content %}
{{ object }}
{% endblock %}
Where navigation is perhaps a context_processor variable holding all the pages, and object is the current PageDetailView object variable
Disclaimer
There are many solutions for your problem as noted by Paulo. Of course this solution assumes that every view holds a page object, a concept usually implemented by a CMS. If you have views that do not derive from the Page app you would have to inject page pretenders within the navigation (atleast holding a get_absolute_url and title attribute).
This might be a very nice learning experience, but you'll probably save loads time installing feinCMS or django-cms which both define an ApplicationContent principle also.
You may use the include tag and pass it a value which is the current page.
For example, this may be a separate file for declaring the menu template only:
menu.html
{% if active = "a" %}
<li>Home</li>
{% if active = "b" %}
<li>page1</li>
{% if active = "c" %}
<li class="active">page2</li>
{% if active = "d" %}
<li>page3</li>
And call this from within your template like this:
{% include 'path/to/menu.html' with active="b"%} # or a or c or d.
Hope it helps!
I want to change the words "Site administration" to something else under the admin page. I tried a couple of grep commands but I couldn't find the right template:
hobbes3#hobbes3 ~/Sites/mysite/site-packages/django/contrib/admin/templates $ grep -ri "site administration" .
hobbes3#hobbes3 ~/Sites/mysite/site-packages/django/contrib/admin/templates $ grep -ri "administration" .
./admin/base_site.html:<h1 id="site-name">{% trans 'Django administration' %}</h1>
hobbes3#hobbes3 ~/Sites/mysite/site-packages/django/contrib/admin/templates $ grep -ri "site" .
./admin/404.html:{% extends "admin/base_site.html" %}
./admin/500.html:{% extends "admin/base_site.html" %}
./admin/500.html:<p>{% trans "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience." %}</p>
./admin/auth/user/change_password.html:{% extends "admin/base_site.html" %}
./admin/base_site.html:{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}
./admin/base_site.html:<h1 id="site-name">{% trans 'Django administration' %}</h1>
./admin/change_form.html:{% extends "admin/base_site.html" %}
./admin/change_form.html: {% if has_absolute_url %}<li>{% trans "View on site" %}</li>{% endif%}
./admin/change_list.html:{% extends "admin/base_site.html" %}
./admin/delete_confirmation.html:{% extends "admin/base_site.html" %}
./admin/delete_selected_confirmation.html:{% extends "admin/base_site.html" %}
./admin/edit_inline/stacked.html: {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %}
./admin/edit_inline/tabular.html: {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %}
./admin/index.html:{% extends "admin/base_site.html" %}
./admin/invalid_setup.html:{% extends "admin/base_site.html" %}
./admin/login.html:{% extends "admin/base_site.html" %}
./admin/object_history.html:{% extends "admin/base_site.html" %}
./admin/object_history.html: <p>{% trans "This object doesn't have a change history. It probably wasn't added via this admin site." %}</p>
./registration/logged_out.html:{% extends "admin/base_site.html" %}
./registration/logged_out.html:<p>{% trans "Thanks for spending some quality time with the Web site today." %}</p>
./registration/password_change_done.html:{% extends "admin/base_site.html" %}
./registration/password_change_form.html:{% extends "admin/base_site.html" %}
./registration/password_reset_complete.html:{% extends "admin/base_site.html" %}
./registration/password_reset_confirm.html:{% extends "admin/base_site.html" %}
./registration/password_reset_done.html:{% extends "admin/base_site.html" %}
./registration/password_reset_email.html:{% blocktrans %}You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
./registration/password_reset_email.html:{% trans "Thanks for using our site!" %}
./registration/password_reset_email.html:{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
./registration/password_reset_form.html:{% extends "admin/base_site.html" %}
Am I looking at the wrong place or something?
EDIT:
After some digging, I think it has something to do with the {% block content_title %}{% endblock %} inside base.html...
EDIT 2:
Here is a screenshot of the words "Site administration" that I am talking about on the admin's homepage.
Give the docs a read; admin docs and customising look and feel
Its a simple case of setting up a template for the admin which overwrites the default;
The template to customize is admin/index.html. (Do the same as with admin/base_site.html in the previous section -- copy it from the default directory to your custom template directory.) Edit the file, and you'll see it uses a template variable called app_list. That variable contains every installed Django app. Instead of using that, you can hard-code links to object-specific admin pages in whatever way you think is best. Again, don't worry if you can't understand the template language -- we'll cover that in more detail in Tutorial 3.
I went through all the tutorials in the Django docs I linked to a couple of weeks back but can't find an example of a custom Admin template, but this site looks like it'll certainly help you understand it;
http://blog.montylounge.com/2009/07/5/customizing-django-admin-branding/
The title _("Site administration") is defined the sites.py file under contrib/admin/. Either you change that string there and have to remember to change it every time you upgrade Django (not recommended) or you override the base_site.html template and add the title manually there.
Thought I'd add a more up-to-date reference for this old question, seeing as it's still viewed and active, and I find the docs overwhelmingly thorough.
Subclass AdminSite to rename template variables
myapp/admin.py
from django.contrib.admin import AdminSite
from .models import MyModel
class MyAdminSite(AdminSite):
# this is the variable you asked about
site_header = 'Monty Python administration'
admin_site = MyAdminSite(name='myadmin')
admin_site.register(MyModel)
myproject/urls.py
from django.conf.urls import url
from myapp.admin import admin_site
urlpatterns = [
url(r'^myadmin/', admin_site.urls),
]
Ref: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#customizing-adminsite
The properties you can customise on your admin_site are:
site_header, site_title, site_url, index_title, index_template,
app_index_template, empty_value_display, login_template, login_form,
logout_template, password_change_template, password_change_done_template
Extend admin templates
In addition, you can extend the default admin templates:
{% extends "admin/change_form.html" %}
{% block object-tools-items %}
<p>
Let's nuke this block and add custom content!
The rest of the default change_form template remains the same.
</p>
{% endblock %}
Ref: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-admin-templates
Another example of this is adding a custom stylesheet:
{% extends "admin/base.html" %}
{% load static %}
{% block extrahead %}
<link rel="stylesheet" href="{% static "my-app/admin-custom.css" %}">
{% endblock %}
This shows an override for all instances of change_form, but you can also override the templates in individual ModelAdmin and TabularInline, etc classes.
There's a fair bit of inheritance going on throughout django-admin, so installing Django Debug Toolbar is very helpful for figuring out what to extend (and where your override should be placed in the templates directory).
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!
I'm looking to add an extra set of pages to my auto-generated admin site. I want to generate reports off my models and some logs surrounding it. The actual generating isn't the issue.
How do I:
Make the report output look like it's an admin page, with breadcrumbs, similarly formatted table, etc?
Register the view so it shows up on the front page?
The above answer didn't address question 2, at least directly... the "hack" way to get your custom view to show up as the front page of the admin is probably to just override it in the urlconf:
(r'^admin/$', my.custom.admin.homepage),
before the normal admin line:
(r'^admin/', admin.site.root),
the "right" way to do it, though, is to make your admin a custom instance of AdminSite and override the index_template setting. http://docs.djangoproject.com/en/dev/ref/contrib/admin/#root-and-login-templates
In terms of generating the look and feel of admin, it should be trivial to inherit the parent pages of the admin and insert your own template content into the appropriate blocks.
Take a look at the markup (including id and class attributes) in the default admin pages and try to get an understanding of how things are styled consistently. If you are including the admin CSS on the page you should get an awful lot of it for free.
For further information, take a look at the admin docs: http://docs.djangoproject.com/en/dev/ref/contrib/admin/
Here's a base template to get you started:
{% extends "admin/base_site.html" %}
{% load adminmedia %}
{% block extrahead %}
{% endblock %}
{% block coltype %}flex{% endblock %}
{% block bodyclass %}change-list{% endblock %}
{% block stylesheet %}{% admin_media_prefix %}css/changelists.css{% endblock %}
{% block extrastyle %}
<link rel="stylesheet" type="text/css" href="{{settings.MEDIA_URL}}/stylesheets/extra_admin.css" />
{% endblock %}
{% block breadcrumbs %}<div class="breadcrumbs">Home › {{page_title}}</div>{% endblock %}
{% block content %}
<div id="content-main">
<h1>{{page_title}}</h1>
{{page_content}}
</div>
{% endblock %}