4👍
TLDR: Override change_view
After digging into the source code file django.contrib.admin.option.py
, it appears that saving model and related M2M is being triggered by this code within _changeform_view
:
if all_valid(formsets) and form_validated:
self.save_model(request, new_object, form, not add)
self.save_related(request, form, formsets, not add)
change_message = self.construct_change_message(request, form, formsets, add)
which is getting called by changeform_view
which sets the atomic transaction. This is what I wanted to override so that I can execute publish_event
once things are committed to DB:
@csrf_protect_m
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
with transaction.atomic(using=router.db_for_write(self.model)):
return self._changeform_view(request, object_id, form_url, extra_context)
This code in turn is called by change_view
and add_view
.
def change_view(self, request, object_id, form_url='', extra_context=None):
return self.changeform_view(request, object_id, form_url, extra_context)
Since I’m making only updates(not create) via form, I overrode change_view
to explicitly call publish_event
:
def change_view(self, request, object_id, form_url='', extra_context=None):
change_resp = super(MySampleModelAdmin, self).change_view(request, object_id, form_url, extra_context)
if request.method != 'GET': # since GET also call this and we don't want event published on GET
publish_event()
return change_resp
As soon as change_resp = super(MySampleModelAdmin, self).change_view(request, object_id, form_url, extra_context)
is done with execution, transaction is committed, so it’s safe to call publish_event
at this step. After this change_view
just expects a response in return.
EDIT:
Tried on_commit, and this seems to work too. This is based on signals.
from django.db import transaction
@receiver(post_save, sender='app.MySampleModel')
def send_model_save_event(sender, instance=None, created=False, **kwargs):
if instance is None:
log.info('Instance is Null')
return
transaction.on_commit(lambda: handle_model_after_save(instance.id))
0👍
transaction.on_commit(lambda: handle_model_after_save(instance.id))
saved my life!