在Python Django中实现SOLID依赖倒置原则时遇TypeError求助
问题描述
我正尝试在Python-Django中实现SOLID原则里的依赖倒置原则,目前遇到如下错误:
TypeError: SignInView.init() missing 1 required positional argument: 'api_response_factory'
我尝试使用抽象方法但未能成功,作为SOLID实现和Python的新手,希望有人能给出解决这类错误的建议或思路。另外,这是我第一次在Stack Overflow提问。
相关代码如下:
from abc import ABC, abstractmethod from rest_framework.views import APIView from django.http import JsonResponse from rest_framework import status class ApiResponseFactoryAbstract(ABC): @abstractmethod def success(self) -> str: pass class ApiResponseFactory(ApiResponseFactoryAbstract): def success(self) -> str: print("Testing") return "Testing" class SignInView(APIView): def __init__(self, api_response_factory: ApiResponseFactoryAbstract): self.api_response_factory = api_response_factory def post(self, request): data = self.api_response_factory.success() return JsonResponse(data=data, status=status.HTTP_200_OK)
app/urls.py内容:
from django.urls import path from . import views router_auth = [ path("sign-in/", views.SignInView.as_view(), name="sign-in"), ]
错误原因与解决方案
错误的核心是:Django REST Framework的APIView通过as_view()实例化时,不会自动传入你自定义的构造函数参数,且你重写__init__时未兼容父类的初始化逻辑。以下是几种适配Django场景的依赖注入方案:
方案1:给构造函数参数添加默认值(快速解决)
给api_response_factory设置默认实例,同时必须调用父类构造函数,保证APIView的初始化逻辑正常运行:
class SignInView(APIView): def __init__(self, api_response_factory: ApiResponseFactoryAbstract = ApiResponseFactory()): super().__init__() # 务必调用父类构造 self.api_response_factory = api_response_factory def post(self, request): data = self.api_response_factory.success() return JsonResponse(data=data, status=status.HTTP_200_OK)
方案2:使用类属性注入(易测试易扩展)
把依赖定义为类属性,既符合DRF视图的使用习惯,又能在测试时灵活替换实现:
class SignInView(APIView): # 默认注入实现,测试时可直接替换 api_response_factory: ApiResponseFactoryAbstract = ApiResponseFactory() def post(self, request): data = self.api_response_factory.success() return JsonResponse(data=data, status=status.HTTP_200_OK)
测试替换示例:
# 测试用的Mock实现 class MockResponseFactory(ApiResponseFactoryAbstract): def success(self) -> str: return "Mocked Success" # 替换视图的依赖 SignInView.api_response_factory = MockResponseFactory()
方案3:使用DRF官方推荐的setup方法(最优解)
DRF视图提供了setup方法用于初始化实例,这是官方推荐的扩展初始化逻辑的方式,避免重写__init__带来的兼容问题:
class SignInView(APIView): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) # 这里可以灵活注入依赖,比如从配置/DI容器中获取 self.api_response_factory = ApiResponseFactory() def post(self, request): data = self.api_response_factory.success() return JsonResponse(data=data, status=status.HTTP_200_OK)
如果后续引入第三方DI库(如dependency-injector),可直接在setup中从容器获取实例,进一步解耦。
依赖倒置原则优化提示
你当前的抽象类定义是合格的,但可以让它更贴合API场景:比如把success方法的返回值改为字典,更适配JsonResponse的需求:
class ApiResponseFactoryAbstract(ABC): @abstractmethod def success(self, data=None) -> dict: pass class ApiResponseFactory(ApiResponseFactoryAbstract): def success(self, data=None) -> dict: response = {"status": "success", "data": data or {}} print(response) return response
内容的提问来源于stack exchange,提问作者Sergio Andres Cortes Romero

