Django example — Dependency Injector 4.46.0 documentation (original) (raw)
This example shows how to use Dependency Injector
with Django.
The example application helps to search for repositories on the Github.
The source code is available on the Github.
Application structure¶
Application has standard Django project structure. It consists of githubnavigator
project package andweb
application package:
./ ├── githubnavigator/ │ ├── init.py │ ├── asgi.py │ ├── containers.py │ ├── services.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── web/ │ ├── templates/ │ │ ├── base.html │ │ └── index.html │ ├── init.py │ ├── apps.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── manage.py └── requirements.txt
Container¶
Declarative container is defined in githubnavigator/containers.py
:
"""Containers module."""
from dependency_injector import containers, providers from github import Github
from . import services
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
github_client = providers.Factory(
Github,
login_or_token=config.GITHUB_TOKEN,
timeout=config.GITHUB_REQUEST_TIMEOUT,
)
search_service = providers.Factory(
services.SearchService,
github_client=github_client,
)
Container instance is created in githubnavigator/__init__.py
:
"""Project package."""
from .containers import Container from . import settings
container = Container() container.config.from_dict(settings.dict)
Views¶
View has dependencies on search service and some config options. The dependencies are injected using Wiring feature.
Listing of web/views.py
:
"""Views module."""
from typing import List
from django.http import HttpRequest, HttpResponse from django.shortcuts import render from dependency_injector.wiring import inject, Provide
from githubnavigator.containers import Container from githubnavigator.services import SearchService
@inject def index( request: HttpRequest, search_service: SearchService = Provide[Container.search_service], default_query: str = Provide[Container.config.DEFAULT_QUERY], default_limit: int = Provide[Container.config.DEFAULT_LIMIT.as_int()], limit_options: List[int] = Provide[Container.config.LIMIT_OPTIONS], ) -> HttpResponse: query = request.GET.get("query", default_query) limit = int(request.GET.get("limit", default_limit))
repositories = search_service.search_repositories(query, limit)
return render(
request,
template_name="index.html",
context={
"query": query,
"limit": limit,
"limit_options": limit_options,
"repositories": repositories,
}
)
App config¶
Container is wired to the views
module in the app config web/apps.py
:
"""Application config module."""
from django.apps import AppConfig
from githubnavigator import container
class WebConfig(AppConfig): name = "web"
def ready(self):
container.wire(modules=[".views"])
Tests¶
Tests use Provider overriding feature to replace github client with a mock web/tests.py
:
"""Tests module."""
from unittest import mock
from django.urls import reverse from django.test import TestCase from github import Github
from githubnavigator import container
class IndexTests(TestCase):
def test_index(self):
github_client_mock = mock.Mock(spec=Github)
github_client_mock.search_repositories.return_value = [
mock.Mock(
html_url="repo1-url",
name="repo1-name",
owner=mock.Mock(
login="owner1-login",
html_url="owner1-url",
avatar_url="owner1-avatar-url",
),
get_commits=mock.Mock(return_value=[mock.Mock()]),
),
mock.Mock(
html_url="repo2-url",
name="repo2-name",
owner=mock.Mock(
login="owner2-login",
html_url="owner2-url",
avatar_url="owner2-avatar-url",
),
get_commits=mock.Mock(return_value=[mock.Mock()]),
),
]
with container.github_client.override(github_client_mock):
response = self.client.get(reverse("index"))
self.assertContains(response, "Results found: 2")
self.assertContains(response, "repo1-url")
self.assertContains(response, "repo1-name")
self.assertContains(response, "owner1-login")
self.assertContains(response, "owner1-url")
self.assertContains(response, "owner1-avatar-url")
self.assertContains(response, "repo2-url")
self.assertContains(response, "repo2-name")
self.assertContains(response, "owner2-login")
self.assertContains(response, "owner2-url")
self.assertContains(response, "owner2-avatar-url")
def test_index_no_results(self):
github_client_mock = mock.Mock(spec=Github)
github_client_mock.search_repositories.return_value = []
with container.github_client.override(github_client_mock):
response = self.client.get(reverse("index"))
self.assertContains(response, "Results found: 0")
Sources¶
Explore the sources on the Github.
Sponsor the project on GitHub: |
---|