如何在 django 原子请求中的事务回滚时保留特定模型的模型更改

问题描述 投票:0回答:1

我有一个 ATOMIC_REQUESTS=True 的 Django 项目。

当身份验证失败时,我需要存储登录尝试的关键数据,这里是示例代码:

class LoginSerializer(serializers.Serializer):
  ...
  
  def validate(self, data):
    ...
    user = authenticate(email=email, password=password)
    if user is None:
      failed_login_attempt(email)
      raise serializers.ValidationError("Invalid credentials")


def failed_login_attempt(email):
  user = User.objects.get(email=email)
  user.lock_status = "LOCKED"
  user.save()

  Device.objects.create(user=user, ip="127.0.0.1", fingerprint="some-fingerprint")

  Activity.objects.create(user=user, type="failed_login_attempt")

限制:

引发 ValidationError 会导致所有更改(包括对 user.lock_status、设备和活动的更新)回滚。由于全局事务,此行为是预期的,但我需要保留这些更改。

我无法删除 ATOMIC_REQUESTS=True,因为它对于应用程序的其他部分至关重要。

目标:

我想确保即使 ValidationError 回滚事务的其余部分,

failed_login_attempt
函数也会持续更改。坚持这些关键变化的最佳方法是什么?

我尝试过的:

  • failed_login_attempt
    包装在
    transaction.atomic()
    中,这不起作用,因为它们仍然是外部事务的一部分。

  • 使用 ATOMIC_REQUESTS=False 的单独数据库配置和自定义数据库路由器,如本asnwer所示,但是:

    这需要其他模型(用户、设备)的广泛权限,这将允许在全局事务之外进行写入。 我无法将这种方法仅限于特定功能(failed_login_attempt),从而导致控制范围过于广泛。

绕过 ORM 并使用原始 SQL

connections.cursor()
感觉像是一种 hack,所以我宁愿避免它。

django postgresql django-models django-rest-framework django-views
1个回答
0
投票

似乎您可以通过在要保留更改的每个视图上使用

django.db.transaction.non_atomic_requests
装饰器来解决此问题。

此装饰器将否定给定视图的 ATOMIC_REQUESTS 的效果。

请参阅文档

© www.soinside.com 2019 - 2024. All rights reserved.