과거 프로젝트에서 클래스별 공통되는 부분을 따로 BaseClass로 만들어서 상속받아서 사용했던 기억이 있는데, BaseClass를 만들어 관리하니 고정된 계층, 즉 상속으로 인해 유연성이 떨어지는 단점이 있었고 조금만 복잡해지면 스파게티 코드가 될것같다는 생각이 들었었는데 이번에 Mixin이라는 개념에 대해서 자세히 공부하면서 얼마나 멍청하게 구현했었는지 생각하게 되었다.
Mixin은 클래스 기반 뷰에서 자주 사용되는 개념으로, 다중 상속을 통해 재사용 가능한 코드를 작성하고 클래스 간에 공통 기능을 공유할 수 있도록 한다. Mixin은 단독으로 사용되기보단 다른 뷰 클래스와 결합하여 사용된다.
이글에서는 Logging Mixin을 이용해서 CRUD Mixin에 믹스인을 적용시키고 View가 처리될때마다 Logging Mixin기능을 사용할 수 있도록 하려고한다.
Mixin의 기본 개념
Mixin은 하나의 독립적인 클래스가 아닌, 여러 클래스에 공통적으로 포함될 수 있는 기능을 제공하는 클래스이다. Django에서는 보통 View와 결합하여 사용된다.
Logging Mixin
아래 코드는 로깅 기능을 추가하기 위해서 작성한 mixin이다
class LoggerMixin:
__pid = os.getpid()
def _get_formatted_string(
self: GenericViewSet | Optional["LoggerMixin"], payload: OrderedDict | ReturnDict, _type: str, **kwargs
):
return (
f"[{_type.upper()}:{self.__pid}]:"
+ f"[{self.action}]:[{self.request._request.path}] - "
+ f"[{'HEADER' if _type == 'header' else 'PAYLOAD'}:{payload}]"
)
def header_logger(self: GenericViewSet | Optional["LoggerMixin"]):
logger.info(self._get_formatted_string(self.request.headers, _type="header"))
def request_logger(self, payload: OrderedDict = None):
logger.info(self._get_formatted_string(payload, _type="request"))
def response_logger(self: GenericViewSet | Optional["LoggerMixin"], payload: ReturnDict = None):
if "list" in self.action:
payload = json.loads(json.dumps(payload))
elif not payload:
pass
else:
payload = dict(payload)
logger.info(self._get_formatted_string(payload, _type="response"))
각 메서드는 해더 정보, 요청 본문의 정보, 응답 본문의 정보를 로깅해주는 기능을 한다.
CRUD를 전부 보여줘도 되지만, 같은 맥락으로 진행되기 때문에 CREATE에 대해서만 예시를 작성한다.
Create Mixin
class CreateModelMixin(mixins.CreateModelMixin, LoggerMixin):
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self: GenericViewSet | LoggerMixin, serializer):
self.header_logger()
self.request_logger(payload=self.request.data)
serializer.save()
self.response_logger(payload=serializer.validated_data)
이렇게 해둠으로써 CreateModelMixin을 상속받아서 View에서 사용하면 perform_create에서 자동으로 logging을 출력해주게 된다.
'BackEnd > Django, DRF' 카테고리의 다른 글
[JWT] Custom JWT 관련 middleware와 backend (0) | 2024.05.31 |
---|---|
[회고록] 효율적인 Django 시작하기: initialize_django 프로젝트 (0) | 2024.05.27 |
[Custom] Django와 CustomJWT로 안전한 인증 시스템 구축하기 (0) | 2024.05.23 |
[Custom] Django와 DRF에서 커스텀 예외처리하기(custom_exception) (0) | 2024.05.16 |
[TEST] 테스트 DB 없이 Django에서 유닛 테스트 수행하기 (0) | 2024.05.14 |