Create custom buttons in admin change_form in Django
I want to add custom buttons to the add/change form at the administration interface. By default, there are only three:
Save and add another
Save and continue editing
Save
I have created some custom methods in my forms.py
file, and I want to create buttons to call these methods. I have used the开发者_运维知识库 snippet http://djangosnippets.org/snippets/1842/, but it's not exactly what I want. This one allows to create buttons and call methods from the admin.py
file and not forms.py
.
Is there a way to do that?
This is my admin.py
code:
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = { "alias": ("title",) }
form = CategoryForm
admin.site.register(Category, CategoryAdmin)
And my forms.py
code:
class CategoryForm(forms.ModelForm):
"""
My attributes
"""
def custom_method(self):
print("Hello, World!")
How do I create a button that calls "custom_method()"?
One simple way I found to add buttons is to add another row for the custom buttons. Create an admin directory in your template dir based on your needs. For example I usually add buttons for specific models in a custom template. Make a "templates/admin/app/model/" directory.
Then add a file change_form.html.
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block submit_buttons_bottom %}
<div class="submit-row">
<input type="button" value="{% trans 'Another Button' %}" name="_anotherbutton" />
</div>
{{ block.super }}
{% endblock %}
The code before the {{ block.super }}
is inspired by the submit_line.html template used by the template tag {% submit_row %}
. I prefer this method because is straightforward but you must live with another row of buttons.
You can override admin/change_form.html
. Copy the version in contrib.admin.templates
into your project. Mine is myproject/templates/admin/change_form.html
, but you could use /myproject/myapp/templates/admin/change_form.html
.
Next, edit the copy and change the two references to the existing template tag, {% submit_row %}
, to point to your own template tag, {% my_template_tag %}
.
Base your template tag on the contrib.admin
's {% submit_row %}
, but edit the HTML template to contain any extra buttons you want to display.
The submit buttons in a change form are rendered by the submit_row
template tag. This tag renders the template admin/submit_line.html
. Since you want to add to the existing buttons, your best (and DRYest) approach is to override admin/submit_line.html
.
For example, create a file my_project/templates/admin/submit_line.html
with the following content:
{% load i18n admin_urls %}
<div class="submit-row">
{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" {{ onclick_attrib }}/>{% endif %}
{% if show_delete_link %}<p class="deletelink-box"><a href="{% url opts|admin_urlname:'delete' original.pk|admin_urlquote %}" class="deletelink">{% trans "Delete" %}</a></p>{% endif %}
{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" {{ onclick_attrib }}/>{%endif%}
{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" {{ onclick_attrib }}/>{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" {{ onclick_attrib }}/>{% endif %}
<input type="submit" value="{% trans 'New button 1' %}" name="_button1" {{ onclick_attrib }}/>
<input type="submit" value="{% trans 'New button 2' %}" name="_button2" {{ onclick_attrib }}/>
</div>
Most of what's above was copied from django/contrib/admin/templates/submit_line.html
. You can also add additional if
statements in the template if you only want to show those additional buttons in certain cases.
You can add a custom button at the bottom of "Add" form and "Change" form for a specifc admin.
First, in the root django project directory, create "templates/admin/custom_change_form.html" as shown below:
Next, under "django" library, there is "change_form.html" which is "django/contrib/admin/templates/admin/change_form.html" so copy & paste all the code of "change_form.html" to "custom_change_form.html" as shown below:
# "templates/admin/custom_change_form.html"
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_modify %}
{% block extrahead %}{{ block.super }}
<script src="{% url 'admin:jsi18n' %}"></script>
{{ media }}
{% endblock %}
... Much more code below
Next, there is the code in line 64 on "custom_change_form" as shown below:
# "templates/admin/custom_change_form.html"
{% block submit_buttons_bottom %}{% submit_row %}{% endblock %} # Line 64
Then, add the code below between "{% submit_row %}" and "{% endblock %}":
{% if custom_button %}
<div class="submit-row">
<input type="submit" value="{% translate 'Custom button' %}" name="_custom_button">
</div>
{% endif %}
So, this is the full code as shown below:
# "templates/admin/custom_change_form.html"
{% block submit_buttons_bottom %} # Line 64
{% submit_row %}
{% if custom_button %}
<div class="submit-row">
<input type="submit" value="{% translate 'Custom button' %}" name="_custom_button">
</div>
{% endif %}
{% endblock %}
Next, this is the settings for templates in "settings.py":
# "settings.py"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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',
],
},
},
]
Then, add "os.path.join(BASE_DIR, 'templates')" to "DIRS" as shown below:
# "settings.py"
import os # Here
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(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',
],
},
},
]
Now, this is "Person" model as shown below:
# "models.py"
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
Then, this is "Person" admin as shown below:
# "admin.py"
from django.contrib import admin
from .models import Person
@admin.register(Person) # Here
class PersonAdmin(admin.ModelAdmin):
pass
So next, for "Person" admin, set "admin/custom_change_form.html" to "change_form_template", set "True" to "extra_context['custom_button']" in "changeform_view()" and set "response_add()" and "response_change()" to define the action after pressing "Custom button" on "Add" form and "Change" form respectively as shown below. *Whether or not setting "response_add()" and "response_change()", inputted data to fields is saved after pressing "Custom button" on "Add" form and "Change" form respectively:
# "admin.py"
from django.contrib import admin
from .models import Person
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
change_form_template = "admin/custom_change_form.html" # Here
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
extra_context = extra_context or {}
extra_context['custom_button'] = True # Here
return super().changeform_view(request, object_id, form_url, extra_context)
def response_add(self, request, obj, post_url_continue=None): # Here
if "_custom_button" in request.POST:
# Do something
return super().response_add(request, obj, post_url_continue)
else:
# Do something
return super().response_add(request, obj, post_url_continue)
def response_change(self, request, obj): # Here
if "_custom_button" in request.POST:
# Do something
return super().response_change(request, obj)
else:
# Do something
return super().response_change(request, obj)
Finally, "Custom button" is added at the bottom of "Add" form and "Change" form for "Person" admin as shown below:
In addition, for "Person" admin, you can replace "changeform_view()" with "render_change_form()" set "context.update({"custom_button": True})" as shown below:
# "admin.py"
from django.contrib import admin
from .models import Person
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
change_form_template = "admin/custom_change_form.html"
def render_change_form(self, request, context, add=False, change=False, form_url="", obj=None):
context.update({"custom_button": True}) # Here
return super().render_change_form(request, context, add, change, form_url, obj)
def response_add(self, request, obj, post_url_continue=None):
if "_custom_button" in request.POST:
# Do something
return super().response_add(request, obj, post_url_continue)
else:
# Do something
return super().response_add(request, obj, post_url_continue)
def response_change(self, request, obj):
if "_custom_button" in request.POST:
# Do something
return super().response_change(request, obj)
else:
# Do something
return super().response_change(request, obj)
Then, "Custom button" is added at the bottom of "Add" form and "Change" form for "Person" admin as well as shown below:
精彩评论