在Django中,如何线程安全地将请求传递给admin.StackedInline表单的__init__?

1 投票
2 回答
539 浏览
提问于 2025-04-17 17:10

我想在我的表单集中给 StackedInline 的表单传递一个请求。现在我有了:

from django.contrib import admin
from django.utils.functional import curry


class AlbumInline(admin.StackedInline):
    form = AlbumAdminForm
    model = Album
    extra = 1

    def get_formset(self, request, obj=None, **kwargs):
        formset = super(AlbumInline, self).get_formset(request, obj, **kwargs)
        formset.form.__init__ = curry(formset.form.__init__, request=request)
        return formset

这个方法可以用,但这个解决方案安全吗?如果不安全,我该怎么修复它呢?

2 个回答

0

我觉得这个不是线程安全的,因为它使用了柯里化,这会把请求绑定在一起。

不过因为它是在管理后台,所以可能也没什么大问题。

1

这看起来不是线程安全的。根据你想从HTTP请求对象中使用什么,你可以把它复制到一个新的HttpRequest中,只保留线程安全的信息(也就是大部分信息,除了请求的线程锁)。

在我的情况下,我是这样做的:

METACOPY = ['HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', 'REMOTE_HOST', 'SERVER_NAME', 'SERVER_PORT', 'LANG', 'LANGUAGE', 'HTTP_REFERER']
def thread_safe_copy(self):
    meta = dict([(k,self.META[k]) for k in METACOPY if k in self.META and isinstance(self.META[k], str)])
    request = HttpRequest()
    request.POST = self.POST
    request.GET = self.GET
    request.user = self.user
    request.path = self.path
    request.META = meta
    ...
    return request

在这里,我对HttpResponse和WSGIResponse进行了修改,但你可以用请求实例来替换self。

撰写回答