在并发请求的情况下,在 Django 应用程序中将数据存储在 "thread local storage" 中是否安全?

Is storing data in "thread local storage" in a Django application safe, in cases of concurrent requests?

我在很多地方看到使用线程本地存储在 Django 应用程序中存储任何数据并不是一个好的做法。 但这是我可以存储我的请求的唯一方法 object。我需要存储它,因为我的应用程序具有复杂的结构。而且我无法在每次函数调用或 class 初始化时继续传递请求 object。

我需要来自我的请求 object 的 cookie 和 headers 传递给我在应用程序的不同位置进行的一些 api 调用。

我正在使用这个作为参考: https://blndxp.wordpress.com/2016/03/04/django-get-current-user-anywhere-in-your-code-using-a-middleware/

所以我正在使用参考资料中提到的中间件。 而且,这就是请求的存储方式

from threading import local
_thread_locals = local()
_thread_locals.request = request

而且,这是获取数据的方式:

getattr(_thread_locals, "request", None)

那么数据是否存储在该特定请求的本地线程中?或者如果同时发生另一个请求,它们是否都使用相同的数据?(这当然不是我想要的)

或者有什么新方法可以解决这个老问题(全局存储请求object)

注意:我还在我的 Django 应用程序中的某些地方使用了 async(如果重要的话)。

是的,在 Django 中使用 thread-local 存储是安全的。

Django 使用一个线程来处理每个请求。 Django 本身也使用 thread-local 数据,例如 storing the currently activated locale. While appservers such as Gunicorn and uwsgi 可以配置为使用多个线程,每个请求仍将由一个线程处理。

但是,there have been conflicting opinions on whether using thread-locals is an elegant and well-designed solution. The reasons against using thread-locals boil down to the same reasons why global variables are considered bad practice. This answer 讨论了其中的一些。

尽管如此,将 request 对象存储在 thread-local 数据中已成为 Django 社区中广泛使用的模式。甚至有一个应用程序 Django-CRUM 包含 CurrentRequestUserMiddleware class 和函数 get_current_user()get_current_request().

请注意,从 3.0 版本开始,Django 已开始实现 asynchronous support。我不确定它对 Django-CRUM 这样的应用有何影响。然而,在可预见的未来,thread-locals 可以安全地与 Django 一起使用。