This project is an experiment in using "ports and adapters" style architecture with the Django framework. The example is a note-taking app called Topsy, which allows users to create notes, organize them into boards, and share them with other users. For the purposes of the example, we're assuming a (non-existent) single page web app that fetches data from Django views which return JSON.
The project consists of two Django apps:
-
notes: handles content creation, viewing, and management
-
accounts: handles account creation and management
In addition to the standard models and views within each app, you will find files containing entities and use cases.
Entities are simple value object classes that correspond to the models.
Use cases are functions that manipulate entities according to the business rules of the app. The use cases are methods of a class that is instantiated with a storage adapter, allowing us to decouple them from the Django ORM.
Actions are wrappers around use cases that run code whenever a use case is called. We use this abstraction to standardize logging and permissions handling for use cases. Generally, an aciton should be used whenever a user is directly invoking a use case, but if it is being called for another reason (e.g. from within another use case) we may want to bypass the action and call it directly.
The views are responsible for passing user input to use cases and returning the result of the use case to the user (or returning an error). No business logic code is stored in Django views or models, thus decoupling all domain code from the framework, and from any knowledge of the storage and HTTP layers.
-
Leonardo Giordani wrote a post and published a repo applying this architecture to Flask
-
Jordi Fierro wrote a post and published a repo exploring the same ideas with Django