在并发请求的情况下,将数据存储在 Django 应用程序的“线程本地存储”中是否安全?

ezv*_*ine 4 python django python-multithreading python-3.x django-rest-framework

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

我需要将请求对象中的 cookie 和标头传递给我在应用程序中不同位置进行的一些 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
Run Code Online (Sandbox Code Playgroud)

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

getattr(_thread_locals, "request", None)
Run Code Online (Sandbox Code Playgroud)

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

或者有没有新的方法来处理这个老问题(全局存储请求对象)

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

hed*_*gie 13

是的,在 Django 中使用线程本地存储是安全的。

Django 使用一个线程来处理每个请求。Django 本身还使用线程本地数据,例如用于存储当前激活的区域设置虽然Gunicornuwsgi等应用程序服务器可以配置为利用多个线程,但每个请求仍将由单个线程处理。

然而,对于使用线程局部变量是否是一个优雅且设计良好的解决方案,存在着相互矛盾的观点。反对使用线程局部变量的原因归结为全局变量被认为是不好的做法的相同原因。这个答案讨论了其中的一些。

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

请注意,从 3.0 版本开始,Django 已经开始实现异步支持。我不确定它对 Django-CRUM 这样的应用程序有何影响。然而,在可预见的未来,线程局部变量可以安全地与 Django 一起使用。