gpt4 book ai didi

Django(v2.0.7) 管理员 : Callback post DB transaction commit

转载 作者:行者123 更新时间:2023-12-04 17:20:34 25 4
gpt4 key购买 nike

我有一个巨大的模型,有很多属性,包括多个 ManyToManyMapping。应用程序中的大部分添加/更新都是通过 REST API 进行的,但对于较小的更正,我使用了 Django Admin Form。此管理表单也有多个内联表单集。

在通过表单或 REST API 更新模型后,我想向 Kafka(publish_event) 发布一些事件。我希望在事务提交给数据库时发生这种情况,以便监听 Kafka 事件的服务不会最终从数据库中获取陈旧数据。

我提到了这个SO post但它似乎在每笔交易中都这样做,而不是在每个模型的基础上,并且有 on_commit造成事物被调用两次的问题(更多内容见下文)。

到目前为止我尝试过的事情:

  1. 信号:由于添加 ManyToManyMapping 而被拒绝,model.save() 需要调用两次,最终发布了 2 个事件。此外,它在模型保存而不是事务提交上运行,因此在回滚的情况下,我仍然会发布一个事件。

  2. 覆盖模型的 save(self, *args, **kwargs): 方法:因 model.save() 被调用两次而被拒绝。

  3. 覆盖 ModelAdmin 的 save_model:这是当我们在表单上点击保存时首先要调用的事情之一,所以重写它没有帮助,因为表单集还没有被处理。因此,包括 M2M 映射在内的完整状态不会在数据库中提交。

def save_model(self, request, obj, form, change):
super().save_model(请求、对象、表单、更改)
发布事件()

  1. 覆盖 ModelAdmin 的save_related:起初这似乎是解决方案,但是事务还没有提交给数据库。
    def save_related(self, request, form, formsets, change):
    表格.save_m2m()
    对于表单集中的表单集:
    self.save_formset(请求,表单,表单集,更改=更改)
    发布事件()
    到目前为止,我还没有弄清楚事务提交后触发的任何回调。

最佳答案

TLDR:覆盖 change_view


深入研究源代码文件 django.contrib.admin.option.py 后,似乎保存模型和相关的 M2M 是由 _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)

它被设置原子事务的 changeform_view 调用。这是我想要覆盖的内容,以便在事情提交给 DB 后我可以执行 publish_event:

@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)

此代码依次由 change_viewadd_view 调用。

def change_view(self, request, object_id, form_url='', extra_context=None):
return self.changeform_view(request, object_id, form_url, extra_context)

因为我只是通过表单进行更新(而不是创建),所以我覆盖了 change_view 以显式调用 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

一旦 change_resp = super(MySampleModelAdmin, self).change_view(request, object_id, form_url, extra_context) 执行完毕,事务就提交了,所以调用 publish_event 是安全的 在这一步。在此 change_view 之后,只需要返回响应。


编辑:试过on_commit ,这似乎也有效。这是基于信号。

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))

关于Django(v2.0.7) 管理员 : Callback post DB transaction commit,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53918542/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com