0
1

More than 1 year has passed since last update.

Dependency Injectionをdjangoプロジェクトに導入してみる

Posted at

DIとは

  • Dependency Injectionの略称
  • 日本語:依存性注入
  • DIとは、プログラミングにおけるデザインパターン(設計思想)の一種で、オブジェクトを成立させるために必要となるコードを実行時に注入(Inject)してゆくという概念のことである。

python用DIライブラリ

導入してみる

コンポーネント構成

DI_component.drawio.png

ファイル構成

./
├── example/
│   ├── __init__.py
│   ├── containers.py
│   ├── controller.py
│   └── api_view.py
├── datalayer.py
├── awslayer.py
├── config.ini
└── requirements.txt

コンテナー作成

"""Containers module."""

import logging.config
import sqlite3

import boto3
from dependency_injector import containers, providers
from . import Controller


class Container(containers.DeclarativeContainer):

    config = providers.Configuration(ini_files=["config.ini"])

    # Gateways

    database_client = providers.Singleton(
        sqlite3.connect,
        config.database.dsn,
    )

    aws_s3_client = providers.Singleton(
        boto3.client,
        service_name="s3",
        aws_access_key_id=config.aws.access_key_id,
        aws_secret_access_key=config.aws.secret_access_key,
    )

    controller = providers.Factory(
        Controller,
        db = database_client,
        s3 = aws_s3_client
    )

コンテナー利用

api_view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from containers.py import Container

class Contents(APIView):
    def get(self, request, **kwargs):
        user = kwargs["user"]
        container = Container()
        content_controller = container.controller()
        # userのコンテンツを取得
        contents = content_controller.get_contents(user)
        return Response(contents)

DI導入後の構成図

DI_component.drawio2.png

単体テストを書く

api_view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from controller.py import Controller

class Contents(APIView):
    def get(self, request, **kwargs):
        user = kwargs["user"]

        content_controller = controller()
        # userのコンテンツを取得
        contents = content_controller.get_contents(user)
        return Response(contents)

  • DI導入前のコードに対して、content_controller = controller()をmockすることがとても難しい
  • DI導入後は、controllerをoverrideしてmockすることが簡単
test_api_view.py
def test_view_get():
    container = Container()
    with container.controller.override(controller_mock):
        api_view = Contents()
        api_view.get()

課題

  • container作成する時に、全てのconfig導入
  • AWS Parameter Storeと環境変数と合わせて、config導入
  • マルチコンテナー構成
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1