在模型管理器中访问Django请求

yr9zkbsy  于 2023-05-01  发布在  Go
关注(0)|答案(1)|浏览(82)

我有一个模型,在我的代码库中有300多个地方被调用,每个模型都必须默认地被company_filter过滤,没有例外。我需要的值从请求即tenant_idtenant_type,这些值是在每个请求可用。我使用tenant_id过滤Company模型,然后将companytenant_idtenant_type传递给过滤器,然后过滤查询集,这似乎工作得很好,但我不确定内存泄漏和请求可能会混淆不同的用户?是否有更好的方法来实现这一点,或者这是一个有效的方法?

中间件

import threading

_thread_local = threading.local()

class RequestMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        _thread_local.request = request

        response = self.get_response(request)

        # Free up the memory after view is returns
        del _thread_local.request

        return response

def get_request():
    return getattr(_thread_local, 'request', None)

型号

class TariffrateCompanyManger(models.Manager):
    # Filters the tariff by the company by default
    def get_queryset(self):
        from config.middleware import get_request

        request = get_request()

        company = Company.objects.get_company_tenant_id(request.tenant_id)

        company_filter = tariff_company_filter(company, request.tenant_id, request.tenant_type)

        if request:
            qs = super().get_queryset().filter(company_filter)
        else:
            qs = super().get_queryset()

        return qs
v8wbuo2f

v8wbuo2f1#

如何在每个请求上过滤查询集取决于您的项目。
首先,与当地人合作并不是一个好的解决方案。有很多问题,而且不安全,如果你真的想使用 *“线程安全”本地代码 *,请使用_active fom django。这是你的locals,以更好的形式:

from django.utils.trans.trans_real import _active

class RequestMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        _active.request = request

        response = self.get_response(request)

        # Free up the memory after view is returns
        return response

def get_request():
    return getattr(_active, 'request', Request())

顺便说一句,如果你返回Default request而不是None,你的代码会工作得更好,你只返回一种类型的数据-“请求”。而不是两个:“请求”和“无”
但是再一次-这是一个错误的方法,过滤BASE查询集,这应该对所有请求都是相同的。

如何解决这些问题:

首先,一些准备工作:
不要使用manager,也不要通过TariffrateCompanyQueryset定义manager。它可以帮助您进行查询集更改。

class TarifRateCompanyQueryset(models.Queryset):

    def filter_by_company(self, request):
        company_filter = Q()
        if hasattr(request, 'tenant_id'):
            company_filter &= Q(tenant_type=request.tenant_type,                
                            company__tarif__tennant_id==request.tenant_id)

        return self.filter()

我不与数据库创建过滤器,它给予你-1命中数据库。不要忘记以正确的形式声明“objects”:

class TarifRateCompany(models.Model):
    ...
    objects = TarifRateCompanyQueryset.as_manager()
    ...

在那之后,尝试看看,你需要过滤的queryset:
Django.Admin:

def get_queryset(self, request):
    return super().get_queryset(request).filter_by_company(request)

Django.ModelView:

def get_queryset(self):
    return super().get_queryset().filter_by_company(self.request)

Django-RestFramework:

class FilterByCompanyBackend(BaseFilterBackend):
    
    def filter_queryset(self, request, queryset, view):
        return queryset.filter_by_company(request)

Django表单:

MyFormCls = modelform_factory(Company, formfield_callback=lambda *args, **kwargs: MyFunc(request, *args, **kwargs))

其中MyFunc得到request并形成fields,如果有,可以对TarifRateCompany字段的queryset进行排序。更多内容:关于ModelformFactory
当然,我使用Mixin来改变许多模型中的基本查询集过滤器。在我的小项目中,我在197个文件中的1261个地方通过请求过滤queryset。在Mixin,我只有一个地方做它。

相关问题