EDIT:
As of Django 3.1, the approach from the original question should simply work:
...
extra_context['show_save_and_add_another'] = False
...
See this Django commit for details.
OLD ANSWER:
summary
Some additional options:
Set save_as=True
on your ModelAdmin
. As described in the docs, this will replace the "Save and add another" button with a "Save as new" button. This may not be ideal for all cases, but it is the simplest solution as far as I know.
Apply a monkey patch for the has_add_permission
method on your ModelAdmin
, so it returns False
during the call to super().change_view
(or changeform_view
).
Override the TemplateResponse.content
(docs) to simply hide (or remove) the submit-row
element, which contains the buttons, from the HTML.
details option 1
The simplest option is to set save_as=True
on the ModelAdmin
. This will replace the "Save and add another" button with a "Save as new" button. As a result, assuming the other save buttons have been disabled, any changes made to the current object can only be saved as a new object. The current object will remain unchanged.
Basic implementation:
class MyModelAdmin(ModelAdmin):
save_as = True
# your other code here, such as the extended changeform_view
details option 2
The submit_line.html template shows which context variables are used to show/hide the save and delete buttons. Most of those context variables can be set via the extra_context
in changeform_view
(or change_view
). However, as the OP showed, we cannot simply override show_save_and_add_another
in that manner.
As pointed out in @Oluwafemi-Sule's answer,
show_save_and_add_another
is set in admin_modify.py, which creates the context for submit_line.html.
Upon closer inspection of the source, it is tempting to override the has_add_permission
context variable, because that determines the value of show_save_and_add_another
. However, simply adding has_add_permission=False
to extra_context
does not work in Django < 2.1
, because the change will be undone by the ModelAdmin.render_change_form method.
Fortunately, rather than overriding the template or patching the template tags, we can simply trick Django into thinking that has_add_permission
is False
, using a monkey patch in change_view
:
def change_view(self, request, object_id=None, form_url='', extra_context=None):
# use extra_context to disable the other save (and/or delete) buttons
extra_context = dict(show_save=False, show_save_and_continue=False, show_delete=False)
# get a reference to the original has_add_permission method
has_add_permission = self.has_add_permission
# monkey patch: temporarily override has_add_permission so it returns False
self.has_add_permission = lambda __: False
# get the TemplateResponse from super (python 3)
template_response = super().change_view(request, object_id, form_url, extra_context)
# restore the original has_add_permission (otherwise we cannot add anymore)
self.has_add_permission = has_add_permission
# return the result
return template_response
This also works if you replace change_view
by changeform_view
, as used by the OP (source).
Note: obviously, this option can only be used if has_add_permission=False
does not interfere with other things in your change view.
details option 3
Based on this example from the docs, it is also possible simply to hide (or even remove) the submit-row
from the rendered HTML for the change_view
:
def change_view(self, request, object_id=None, form_url='',
extra_context=None):
# get the default template response
template_response = super().change_view(request, object_id, form_url,
extra_context)
# here we simply hide the div that contains the save and delete buttons
template_response.content = template_response.rendered_content.replace(
'<div class="submit-row">',
'<div class="submit-row" style="display: none">')
return template_response
As noted, we can also remove the submit-row
section altogether, but that is a bit more work.
This is simpler than option 2, but more fragile.