{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":""},{"location":"#django-project-structure","title":"Django Project Structure","text":"
This is a template/project structure for developing django-based applications - using django-rest-framework
along with django
.
The project is meant to be easily clone-able, and used as the starter template for the next big thing you develop. Note, this is a folder structure only, not \u201cbest practices\u201d.
"},{"location":"#some-batteries-included","title":"Some batteries included:","text":"python manage.py runserver
and you should see the default success page provided by Django at http://127.0.0.1:8000/.DATABASE
section of settings.py
we have added postgresql
as the default DATABASE
(As most of the application are using it). You can roll back to the sqlite
by adding the following code snippet, removing the current one.DATABASES = {\n 'default': {\n 'ENGINE': 'django.db.backends.sqlite3',\n 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),\n }\n}\n
"},{"location":"#creating-an-app","title":"Creating an App","text":"apps
. For example: poll
python manage.py startapp poll apps/poll
from the root directory of the project.\n\u251c\u2500\u2500 apps/\n\u2502 \u2514\u2500\u2500 example/ # A django rest app\n\u2502 \u251c\u2500\u2500 api/\n\u2502 \u2502 \u251c\u2500\u2500 v1/ # Only the \"presentation\" layer exists here.\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 serializers.py\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 urls.py\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 views.py\n\u2502 \u2502 \u251c\u2500\u2500 v2 # Only the \"presentation\" layer exists here.\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 serializers.py\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 urls.py\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 views.py\n\u2502 \u2502 \u2514\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 fixtures/ # Constant \"seeders\" to populate your database\n\u2502 \u251c\u2500\u2500 management/\n\u2502 \u2502 \u251c\u2500\u2500 commands/ # Try and write some database seeders here\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 command.py\n\u2502 \u2502 \u2514\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 migrations/\n\u2502 \u2502 \u2514\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 templates/ # App-specific templates go here\n\u2502 \u251c\u2500\u2500 tests/ # All your integration and unit tests for an app go here.\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 admin.py\n\u2502 \u251c\u2500\u2500 apps.py\n\u2502 \u251c\u2500\u2500 models.py\n\u2502 \u251c\u2500\u2500 services.py # Your business logic and data abstractions go here.\n\u2502 \u251c\u2500\u2500 urls.py\n\u2502 \u2514\u2500\u2500 views.py\n\u251c\u2500\u2500 common/ # An optional folder containing common \"stuff\" for the entire project\n\u251c\u2500\u2500 config/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 asgi.py\n\u2502 \u251c\u2500\u2500 settings.py\n\u2502 \u251c\u2500\u2500 urls.py\n\u2502 \u2514\u2500\u2500 wsgi.py\n\u251c\u2500\u2500 deployments/ # Isolate Dockerfiles and docker-compose files here.\n\u251c\u2500\u2500 docs/\n\u2502 \u251c\u2500\u2500 CHANGELOG.md\n\u2502 \u251c\u2500\u2500 CONTRIBUTING.md\n\u2502 \u251c\u2500\u2500 deployment.md\n\u2502 \u251c\u2500\u2500 local-development.md\n\u2502 \u2514\u2500\u2500 swagger.yaml\n\u251c\u2500\u2500 requirements/\n\u2502 \u251c\u2500\u2500 common.txt # Same for all environments\n\u2502 \u251c\u2500\u2500 development.txt # Only for a development server\n\u2502 \u251c\u2500\u2500 local.txt # Only for a local server (example: docs, performance testing, etc.)\n\u2502 \u2514\u2500\u2500 production.txt # Production only\n\u251c\u2500\u2500 static/ # Your static files\n\u251c\u2500\u2500 .env.example # An example of your .env configurations. Add necessary comments.\n\u251c\u2500\u2500 .gitignore # https://github.com/github/gitignore/blob/main/Python.gitignore\n\u251c\u2500\u2500 entrypoint.sh # Any bootstrapping necessary for your application\n\u251c\u2500\u2500 manage.py\n\u251c\u2500\u2500 pytest.ini\n\u2514\u2500\u2500 README.md\n
"},{"location":"#rationale","title":"Rationale","text":"Each app
should be designed in way to be plug-able, that is, dragged and dropped into any other project and it\u2019ll work independently.
apps
Folder","text":"src
folder. If you really wanted to, you could even call it the src
folder. Again, it's up to you.services
","text":"api
Folder","text":"api
. For example, in this repository it's the example/api
folder. That allows us to isolate our API components in a consistent location. If we were to put it in the root of our app, then we would end up with a huge list of API-specific modules in the general area of the app. That's without getting into the mess of API versioning.For projects with a lot of small, interconnecting apps, it can be hard to hunt down where a particular API view lives. In contrast to placing all API code within each relevant app, sometimes it makes more sense to build an app specifically for the API. This is where all the serializers, renderers, and views are placed. Therefore, the name of the app should reflect its API version
"},{"location":"#api-versioning","title":"API Versioning","text":"It might often be necessary to support multiple versions of an API throughout the lifetime of a project. Therefore, we're adding in support right from the start.
For different API versions, we're assuming the following will change: - Serializers: That is, how the data is presented to a consumer - Views: That is, how the data is accessed and modified by a consumer - URLs: That is, where the consumer access the data
model
s and service
s can be thought of as shared between versions. Therefore, migrating changes should be versioned carefully without breaking different versions of the API. After all, your API version is simply a presentation of how data is handled and managed within your application.
Sufficient unit tests and integration tests should wrap services and API endpoints to ensure full compatibility.
"},{"location":"#whats-v2-of-an-api","title":"What'sv2
of an API?","text":"Currently, we're proposing that major changes to the following constitutes a new API version: 1. Representation of data, either for submission or retrieval 1. Major optimizations 1. Major code reorganization and code refactor 1. Usually, in a Django project, you won't need to worry about API versioning
"},{"location":"#config","title":"config
","text":"base
, local
, production
and development
.~~. Update: As environment specific variables will be handled using environment variables, we've deemed it unnecessary to have separate settings files for now.deployments
","text":"You should probably add a custom exception handler to your project based on who consumes your APIs. To learn how to create a custom exception handler, you can check out the Django Rest Framework documentation at: https://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling
"},{"location":"#faq","title":"FAQ","text":"Why not just make a cookiecutter out of this?
Honestly, GitHub templates are so much easier. It's a one-click solution and you're good to go. If we want to turn this into a cookiecutter, we'd have to also start deciding sensible defaults, for instance, sentry, DRF version, formatters, linters, etc. And that's something better left to the developer. Although, I am playing around with the idea of having a cookiecutter with those sensible defaults, but let's hope we have time to work on it on the cookiecutter
branch.