Django. Customize action for model - python

I need to edit the "Add Object" action in the admin. It needs to redirect the user to a custom cause the logic required for adding objects is too complex to be managed in the admin. So, how do I make this possible? i.e:
The picture shows a django-suit admin, but the question is the same. How can I make that button redirect to a custom url? Or, how can I create a similar button that redirects to a custom url (I could disable the default create and leave only the custom button).

Override change_list_template html, the block object-tools-items. It's where add button is placed.
class MyModelAdmin(admin.ModelAdmin):
change_list_template = 'change_list.html'
In your change_list.html
{% extends "admin/change_list.html" %}
{% load i18n admin_static admin_list %}
{% block object-tools-items %}
{% if has_add_permission %}
<li>
<a href="your/custom/url" class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
{% endif %}
{% endblock %}
You need to add your new html in any dir that is included on TEMPLATE_DIRS options. But, you should do it inside your model's app.
-app
-templates
-admin
change_list.html
Add above dir in TEMPLATE DIRS paths.

Related

Django: Extending base.html in django admin

I've a base.html file which has vertical and horizontal menu-bar:
Wherever I want to use that I just simply write:
{% extends 'base.html' %}
{% block content %}
//html code
{% endblock content %}
But I don't know how to use the same file base.html from templates directory in djando admin.
I want output like this:
What I Tried:
How to override and extend basic Django admin templates?
How do I correctly extend the django admin/base.html template?
Override Navbar in Django base admin page to be same as the base.html
I tried few other solution just don't want to increase the length of question and base.html file's code just has basic bootstrap, html code for menus.
I am new to Django, little explanation would be highly appreciated!
What you are looking is similar to nav-global.
Try this:
First create a folder in your templates folder as admin and create a html file(base_site.html) in the same folder
Assuming you have separate html file for menu-bars(Let's say the file is nav.html).
Write the below code in base_site.html:
{% extends 'admin/base.html' %}
{% block nav-global %}
{% include 'nav.html' %} #Your navigation html file
{% endblock %}
Unrelated to question: I found a git repo which will give you idea how to customize the django-admin menu.
You can just extend the admin's base template as
{% extends "admin/base.html" %}
For example:
{% extends "admin/base.html" %}
{% block sidebar %}
{{ block.super }}
<div>
<h1>Extra links</h1>
My extra link
</div>
{% endblock %}
Also, make sure that you have added the admin app to the INSTALLED_APPS
INSTALLED_APPS = [
# other apps,
'django.contrib.admin',
# other apps,
]
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>
My extra link
</div>
{% endblock %}

Django using more than 1 package for admin site

I am using 2 django packages: Admin sortable (For changing the order of models) and Django import export (For importing csv directly into my models).
The problem is that if I add the 2 packages into my model admin e.g.
class CategoryAdmin(SortableAdmin, ImportExportModelAdmin):
they override each other.
The buttons either show only for the Admin sortable or the Django import export. Is there anyway I can integrate both of them together? Alternatively, is there another package I can swap out so that I can achieve the same functions (1. change the order of models and 2. import csv directly into models)
I was able to solve this by overriding the template used on the page. Both Admin Sortable and Django Import Export override the admin change_list.html template in different ways, which is why they don't play nice together.
I used the adminsortable template as my base (Found in site_packages/adminsortable/templates/adminsortable/change_list_with_sort_link.html), and added some pieces from the django import export template (Found in site_packages/import_export/templates/admin/import_export/change_list_import_export.html) to get this merged template:
{% extends change_list_template_extends %}
{% load i18n %}
{% block object-tools-items %}
{% for sorting_filter in sorting_filters %}
<li>
{% trans 'Change Order of' %} {{ sorting_filter }}
</li>
{% empty %}
<li>
{% trans 'Change Order' %}
</li>
{% endfor %}
{% include "admin/import_export/change_list_import_item.html" %}
{% include "admin/import_export/change_list_export_item.html" %}
{{ block.super }}
{% endblock %}
The lines:
{% include "admin/import_export/change_list_import_item.html" %}
{% include "admin/import_export/change_list_export_item.html" %}
Add the import export buttons to the template.
Then, you need to tell django to use this template. The SortableAdminBase class has a field called sortable_change_list_with_sort_link_template which you can override to use your new custom template. So your admin class will look like:
class CategoryAdmin(ImportExportMixin, SortableAdmin):
sortable_change_list_with_sort_link_template = 'admin/category/change_list_import_export_sortable.html'
Assuming you put your custom template in admin/category/change_list_import_export_sortable.html
If all works well, you should be getting all 3 buttons appearing at the top of your admin page:
Django Import Export Admin Sortable Buttons Screenshot

How to customize breadcrumbs in Django REST Framework Browsable API

Currently the Browsable API seems to derive the breadcrumbs from the classname of my views. However I am using nested resources for my API so I can get Breadcrumbs like:
Root / User List / User Detail / User Invite List / User Invite Detail
However the fact that the 'User Invite'-views show User again is pretty redundant. I would rather have that their breadcrumbs would just be 'Invite List' and 'Invite Detail'.
Now the most obvious solution would ofcourse be to just rename the view classes but that is not an option for me since I also have the classes ChatInviteList and ChatInviteDetail that share the same problem. So I can't name both of them InviteDetail and InviteList.
Is there a way to customize these breadcrumbs in another way? For example by setting some variable in the view class or something. I tried searching the docs but couldn't find anything.
Write a template called 'rest_framework/api.html' (docs) that extends 'rest_framework/base.html' in which you override the breadcrumbs block. For guidance, the original block looks:
{% block breadcrumbs %}
<ul class="breadcrumb">
{% for breadcrumb_name, breadcrumb_url in breadcrumblist %}
{% if forloop.last %}
<li class="active">{{ breadcrumb_name }}</li>
{% else %}
<li>{{ breadcrumb_name }}</li>
{% endif %}
{% endfor %}
</ul>
{% endblock %}

How to remove breadcrumbs in Django admin

How can I use nav-global for navigation and hide the breadcrumbs in the django admin app. I've found ways to do this but they seem hackish and problematic. I'm looking for a clean reliable solution.
Naive Approach that doesn't work:
customize admin/base_site.html
{% extends "admin/base.html" %}
{% load i18n %}
{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}
{% block branding %}
<h1 id="site-name">{% trans 'Django administration' %}</h1>
{% endblock %}
{% block nav-global %}Some links will go here...{% endblock %}
{% block breadcrumbs %}{% endblock %}
this doesn't work because the templates in django admin like change_list.html that extend base_site.html will define content for breadcrumbs which will override whatever I have set in base_site.html.
solution 1: CSS
Add the following css to admin using the extrastyle block. This works, but the breadcrumbs still get generated and appear in the HTML source. This feels hacky.
.breadcrumbs {
display: none;
}
Solution 2: override base.html
Override base.html and remove the breadcrumbs block. Children will try to define it but it never exists so it never gets rendered. This also seems like a hack. It's also not a good idea to override base.html as each Django release can make many changes to base.html and the admin app could break between releases.
Extend all templates that you want to render an empty breadcrumbs block. Your first attempt (you say doesn't work) will work, just extend the other templates as well. Like change_list.html:
{% extends "admin/change_list.html" %}
{% block breadcrumbs %}
{% endblock %}
change_form.html:
{% extends "admin/change_form.html" %}
{% block breadcrumbs %}
{% endblock %}
The same for:
500.html
app_index.html
change_password.html
delete_confirmation.html
delete_selected_confirmation.html
invalid_setup.html
object_history.html
login.html and index.html have an empty breadcrumb block.
Downside is that the templates need to be applied per app. This means duplicated templates. If you want to do project wide with single templates you end up with other hacks: copying the complete original templates OR let the templates extend /path/to/site-packages/django/contrib/admin/templates/template_name.html.
Use CSS. You can also hide app_label which is 2nd child.
.breadcrumbs>ul li:nth-child(2),
#grp-breadcrumbs>ul li:nth-child(2) {
display:none;
}
To avoid the recursion problem:
Install django-apptemplates
pip install django-apptemplates
Add the template loader to your settings.py. If you are using Django >= 1.8, add it in the TEMPLATES setting (more details in the doc).
You can now override a template by adding app_name: in the extends tag:
{% extends "admin:admin/change_form.html" %}
{% block breadcrumbs %}
{% endblock %}

Including Django templates in an arbitrary order

I'm using separate template files to create "widgets" - HTML snippets that are displayed in a grid layout on the page. The main template includes the widget templates like this:
{% include "myapp/widgetA.html" %}
{% include "myapp/widgetB.html" %}
{% include "myapp/widgetC.html" %}
{% include "myapp/widgetD.html" %}
This works fine, but I want the user to be able to change the order that the widgets appear in. I will have the user's preferred ordering stored in a tuple, eg: ('widgetC', 'widgetB', 'widgetA', 'widgetD')
How can I handle this in the template?
You can iterate over the tuple in the template:
{% for widget in my_widgets %}
{% include widget %}
{% endfor %}
where my_widgets = ('myapp/widgetC.html', 'myapp/widgetB.html', 'myapp/widgetA.html', 'myapp/widgetD.html') in your view.

Categories

Resources