django 类型检查错误:浏览次数,py:24:错误:“HttpRequest”没有属性“tenant”

v64noz0r  于 2023-01-31  发布在  Go
关注(0)|答案(1)|浏览(96)

我正在创建一个多租户的Django应用程序,我使用的定制中间件将一个tenant对象附加到请求中。
我的问题是在类型检查时,我的视图没有意识到HttpRequest类上的额外属性。
我尝试过创建一个TenantHttpClass,它扩展了HttpRequest并添加了tenant属性。
编辑:忘了说我正在使用mypy键入check。
我如何让我的视图意识到这一点。我的代码如下:
middleware/main.py

from typing import Type

from django.db import connection
from django.http import Http404
from django.utils.deprecation import MiddlewareMixin

from apps.tenants.custom_request import TenantHttpRequest as HttpRequest
from apps.tenants.models import Domain, Tenant
from apps.tenants.utils import get_public_schema_name, get_tenant_domain_model, remove_www
from vastdesk import settings

class TenantMainMiddleware(MiddlewareMixin):
    TENANT_NOT_FOUND_EXCEPTION: Type[Http404] = Http404
    """
    This middleware should be placed at the very top of the middleware stack.
    Selects the proper database schema using the request host. Can fail in
    various ways which is better than corrupting or revealing data.
    """

    @staticmethod
    def hostname_from_request(request: HttpRequest) -> str:
        """Extracts hostname from request. Used for custom requests filtering.
        By default removes the request's port and common prefixes.
        """
        return remove_www(request.get_host().split(":")[0])

    def get_tenant(self, domain_model: Domain, hostname: str) -> Tenant:
        domain = domain_model.objects.select_related("tenant").get(domain=hostname)
        return domain.tenant

    def process_request(self, request: HttpRequest) -> None:
        # Connection needs first to be at the public schema, as this is where
        # the tenant metadata is stored.

        connection.set_schema_to_public()
        hostname = self.hostname_from_request(request)

        domain_model = get_tenant_domain_model()
        try:
            tenant = self.get_tenant(domain_model, hostname)
        except domain_model.DoesNotExist:
            self.no_tenant_found(request, hostname)
            return

        tenant.domain_url = hostname
        request.tenant = tenant
        connection.set_tenant(request.tenant)
        self.setup_url_routing(request)

    def no_tenant_found(self, request: HttpRequest, hostname: str) -> None:
        """What should happen if no tenant is found.
        This makes it easier if you want to override the default behavior"""
        if (
            hasattr(settings, "SHOW_PUBLIC_IF_NO_TENANT_FOUND")
            and settings.SHOW_PUBLIC_IF_NO_TENANT_FOUND
        ):
            self.setup_url_routing(request=request, force_public=True)
        else:
            raise self.TENANT_NOT_FOUND_EXCEPTION('No tenant for hostname "%s"' % hostname)

    @staticmethod
    def setup_url_routing(request: HttpRequest, force_public: bool = False) -> None:
        """
        Sets the correct url conf based on the tenant
        :param request:
        :param force_public
        """

        # Do we have a public-specific urlconf?
        if hasattr(settings, "PUBLIC_SCHEMA_URLCONF") and (
            force_public or request.tenant.schema_name == get_public_schema_name()
        ):
            request.urlconf = settings.PUBLIC_SCHEMA_URLCONF

custom_request.py

from typing import Union, TYPE_CHECKING
from django.http import HttpRequest

if TYPE_CHECKING:
    from apps.tenants.models import Tenant

class TenantHttpRequest(HttpRequest):
    tenant: Union["Tenant", None]

views.py

from typing import Any, Dict
from django.views.generic import TemplateView

from apps.tenants.models import Tenant as Realm
from apps_tenants.ticket_system.models import Ticket

class StaffDashboardView(TemplateView):
    template_name = "dashboard/dash-staff/dash.html"

    def get_context_data(self, **kwargs: Dict[str, Any]) -> Dict[str, Any]:
        context = super(StaffDashboardView, self).get_context_data(**kwargs)
        context["logo_url"] = Realm.objects.get(
            schema_name=self.request.tenant.schema_name
        ).logo_url
        context["profile_image_url"] = ""
        context["tickets"] = Ticket.objects.all()
        return context

class CustomerDashboardView(TemplateView):
    template_name = "dashboard/dash-customer/dash.html"

    def get_context_data(self, **kwargs: Dict[str, Any]) -> Dict[str, Any]:
        context = super(CustomerDashboardView, self).get_context_data(**kwargs)
        context["logo_url"] = Realm.objects.get(
            schema_name=self.request.tenant.schema_name
        ).logo_url
        context["profile_image_url"] = ""
        context["tickets"] = Ticket.objects.all()
        return context
mzmfm0qo

mzmfm0qo1#

事实证明,这实际上是非常容易修复,只需要添加到我的views.py

from typing import Any, Dict
from django.views.generic import TemplateView

from apps.tenants.models import Tenant as Realm
from apps_tenants.ticket_system.models import Ticket

class StaffDashboardView(TemplateView):
    template_name = "dashboard/dash-staff/dash.html"

    request: TenantHttpRequest

    def get_context_data(self, **kwargs: Dict[str, Any]) -> Dict[str, Any]:
        context = super(StaffDashboardView, self).get_context_data(**kwargs)
        context["logo_url"] = Realm.objects.get(
            schema_name=self.request.tenant.schema_name
        ).logo_url
        context["profile_image_url"] = ""
        context["tickets"] = Ticket.objects.all()
        return context

相关问题