Django example¶
This example shows how to use Dependency Injector with Django.
The example application helps to search for repositories on the Github.
../_images/django.pngThe source code is available on the Github.
Application structure¶
Application has standard Django project structure. It consists of githubnavigator project package and
web 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.""" fromdependency_injectorimport containers, providers fromgithubimport Github from.import services classContainer(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.containersimport 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.""" fromtypingimport List fromdjango.httpimport HttpRequest, HttpResponse fromdjango.shortcutsimport render fromdependency_injector.wiringimport inject, Provide fromgithubnavigator.containersimport Container fromgithubnavigator.servicesimport SearchService @inject defindex( 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.""" fromdjango.appsimport AppConfig fromgithubnavigatorimport container classWebConfig(AppConfig): name = "web" defready(self): container.wire(modules=[".views"])
Tests¶
Tests use Provider overriding feature to replace github client with a mock web/tests.py:
"""Tests module.""" fromunittestimport mock fromdjango.urlsimport reverse fromdjango.testimport TestCase fromgithubimport Github fromgithubnavigatorimport container classIndexTests(TestCase): deftest_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") deftest_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:
[フレーム]