2024-11-05 09:12:04 +00:00
|
|
|
|
[![Python 3.12.3](https://img.shields.io/badge/python-3.12.3-blue.svg)](https://www.python.org/downloads/release/python-3123/)
|
2023-11-26 10:54:19 +00:00
|
|
|
|
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
|
2024-11-05 09:25:10 +00:00
|
|
|
|
[![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://pre-commit.com/)
|
2023-11-26 10:54:19 +00:00
|
|
|
|
|
|
|
|
|
![Django](https://img.shields.io/badge/django-%23092E20.svg?style=for-the-badge&logo=django&logoColor=white)
|
|
|
|
|
![DjangoREST](https://img.shields.io/badge/DJANGO-REST-ff1709?style=for-the-badge&logo=django&logoColor=white&color=ff1709&labelColor=gray)
|
|
|
|
|
![Postgres](https://img.shields.io/badge/postgres-%23316192.svg?style=for-the-badge&logo=postgresql&logoColor=white)
|
|
|
|
|
![Swagger](https://img.shields.io/badge/-Swagger-%23Clojure?style=for-the-badge&logo=swagger&logoColor=white)
|
|
|
|
|
|
|
|
|
|
|
2022-01-25 03:15:53 +00:00
|
|
|
|
# Django Project Structure
|
|
|
|
|
This is a template/project structure for developing django-based applications -
|
2024-11-05 09:25:10 +00:00
|
|
|
|
using `django-rest-framework` along with `django`.
|
2022-01-18 02:27:09 +00:00
|
|
|
|
|
2023-11-26 10:54:19 +00:00
|
|
|
|
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
|
|
|
|
|
“best practices”.
|
|
|
|
|
|
2022-01-26 08:04:30 +00:00
|
|
|
|
|
2024-11-05 09:25:10 +00:00
|
|
|
|
## Some batteries included:
|
|
|
|
|
* [Django Storages](https://django-storages.readthedocs.io/en/stable/) - To integrate with different types of storages
|
|
|
|
|
* [Django Rest Framework](https://www.django-rest-framework.org/) - For API development
|
|
|
|
|
* [Django CORS Headers](https://github.com/adamchainz/django-cors-headers) - To allow requests from other origins
|
|
|
|
|
* [Sentry](https://docs.sentry.io/platforms/python/) - For crashes
|
|
|
|
|
* [Gunicorn](https://gunicorn.org/) - As a web server
|
|
|
|
|
|
|
|
|
|
|
2022-08-09 06:04:56 +01:00
|
|
|
|
## Getting Started
|
2023-11-26 11:00:23 +00:00
|
|
|
|
1. Since this is a template repository, simply hit "Use this template" on GitHub
|
|
|
|
|
and follow the instructions. Otherwise, you can just clone the repo, remove/add
|
|
|
|
|
anything you see fit.
|
|
|
|
|
1. Run the project using `python manage.py runserver` and you should see the
|
|
|
|
|
default success page provided by Django at
|
|
|
|
|
[http://127.0.0.1:8000/](http://127.0.0.1:8000/).
|
2024-11-05 09:12:04 +00:00
|
|
|
|
1. [Optional] If you want to configure database, in the `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.
|
2024-02-03 05:23:27 +00:00
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
DATABASES = {
|
|
|
|
|
'default': {
|
|
|
|
|
'ENGINE': 'django.db.backends.sqlite3',
|
|
|
|
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2022-08-09 06:04:56 +01:00
|
|
|
|
|
|
|
|
|
### Creating an App
|
|
|
|
|
1. Create a folder with the app name in `apps`. For example: `poll`
|
2023-11-26 10:54:19 +00:00
|
|
|
|
1. Run `python manage.py startapp poll apps/poll` from the root directory of the
|
|
|
|
|
project
|
2022-01-26 08:12:22 +00:00
|
|
|
|
|
|
|
|
|
|
2022-01-26 08:04:30 +00:00
|
|
|
|
## Project Tree
|
2023-11-26 10:54:19 +00:00
|
|
|
|
``` bash
|
2022-01-26 08:04:30 +00:00
|
|
|
|
.
|
2024-03-15 12:08:13 +00:00
|
|
|
|
├── apps/
|
|
|
|
|
│ └── example/ # A django rest app
|
|
|
|
|
│ ├── api/
|
|
|
|
|
│ │ ├── v1/ # Only the "presentation" layer exists here.
|
2022-08-09 06:04:56 +01:00
|
|
|
|
│ │ │ ├── __init__.py
|
|
|
|
|
│ │ │ ├── serializers.py
|
|
|
|
|
│ │ │ ├── urls.py
|
|
|
|
|
│ │ │ └── views.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
│ │ ├── v2 # Only the "presentation" layer exists here.
|
2022-08-09 06:04:56 +01:00
|
|
|
|
│ │ │ ├── __init__.py
|
|
|
|
|
│ │ │ ├── serializers.py
|
|
|
|
|
│ │ │ ├── urls.py
|
|
|
|
|
│ │ │ └── views.py
|
|
|
|
|
│ │ └── __init__.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
│ ├── fixtures/ # Constant "seeders" to populate your database
|
|
|
|
|
│ ├── management/
|
|
|
|
|
│ │ ├── commands/ # Try and write some database seeders here
|
2022-08-09 06:04:56 +01:00
|
|
|
|
│ │ │ └── command.py
|
|
|
|
|
│ │ └── __init__.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
│ ├── migrations/
|
2022-01-26 08:04:30 +00:00
|
|
|
|
│ │ └── __init__.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
│ ├── templates/ # App-specific templates go here
|
|
|
|
|
│ ├── tests/ # All your integration and unit tests for an app go here.
|
|
|
|
|
│ ├── __init__.py
|
2022-01-26 08:04:30 +00:00
|
|
|
|
│ ├── admin.py
|
|
|
|
|
│ ├── apps.py
|
|
|
|
|
│ ├── models.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
│ ├── services.py # Your business logic and data abstractions go here.
|
2022-01-26 08:12:22 +00:00
|
|
|
|
│ ├── urls.py
|
2022-01-26 08:04:30 +00:00
|
|
|
|
│ └── views.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
├── common/ # An optional folder containing common "stuff" for the entire project
|
|
|
|
|
├── config/
|
2022-01-26 08:04:30 +00:00
|
|
|
|
│ ├── __init__.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
│ ├── asgi.py
|
|
|
|
|
│ ├── settings.py
|
2022-01-26 08:04:30 +00:00
|
|
|
|
│ ├── urls.py
|
|
|
|
|
│ └── wsgi.py
|
2024-03-15 12:08:13 +00:00
|
|
|
|
├── deployments/ # Isolate Dockerfiles and docker-compose files here.
|
|
|
|
|
├── docs/
|
2022-01-26 08:04:30 +00:00
|
|
|
|
│ ├── CHANGELOG.md
|
|
|
|
|
│ ├── CONTRIBUTING.md
|
|
|
|
|
│ ├── deployment.md
|
|
|
|
|
│ ├── local-development.md
|
|
|
|
|
│ └── swagger.yaml
|
2024-03-15 12:08:13 +00:00
|
|
|
|
├── requirements/
|
|
|
|
|
│ ├── common.txt # Same for all environments
|
|
|
|
|
│ ├── development.txt # Only for a development server
|
|
|
|
|
│ ├── local.txt # Only for a local server (example: docs, performance testing, etc.)
|
|
|
|
|
│ └── production.txt # Production only
|
|
|
|
|
├── static/ # Your static files
|
|
|
|
|
├── .env.example # An example of your .env configurations. Add necessary comments.
|
|
|
|
|
├── .gitignore # https://github.com/github/gitignore/blob/main/Python.gitignore
|
|
|
|
|
├── entrypoint.sh # Any bootstrapping necessary for your application
|
2022-01-26 08:04:30 +00:00
|
|
|
|
├── manage.py
|
|
|
|
|
├── pytest.ini
|
|
|
|
|
└── README.md
|
2022-01-25 03:15:53 +00:00
|
|
|
|
```
|
2022-01-26 08:12:22 +00:00
|
|
|
|
|
2023-11-26 10:54:19 +00:00
|
|
|
|
|
2022-01-26 08:04:30 +00:00
|
|
|
|
## Rationale
|
2022-08-15 04:51:06 +01:00
|
|
|
|
Each `app` should be designed in way to be plug-able, that is, dragged and dropped
|
2022-01-26 08:12:22 +00:00
|
|
|
|
into any other project and it’ll work independently.
|
|
|
|
|
|
2022-01-25 03:15:53 +00:00
|
|
|
|
|
2023-11-26 10:54:19 +00:00
|
|
|
|
### `apps` Folder
|
|
|
|
|
* A mother-folder containing all apps for our project. Congruent to any
|
|
|
|
|
JS-framework's `src` folder. If you really wanted to, you could even call it the
|
|
|
|
|
`src` folder. Again, it's up to you.
|
2024-07-28 21:01:35 +01:00
|
|
|
|
* An app can be a django template project, or a rest framework API.
|
2023-11-26 10:54:19 +00:00
|
|
|
|
|
|
|
|
|
### `services`
|
|
|
|
|
* We’ll be writing business logic in services instead of anywhere else.
|
|
|
|
|
* There's a common argument: "Why not just use model managers?", and honestly,
|
|
|
|
|
that's a fair point. However, for our use case, we've often noticed that a single
|
|
|
|
|
service can leverage more zero to many models. Either way, managers or services,
|
|
|
|
|
both work towards the same goal - isolating business logic away from views, and
|
|
|
|
|
brings it closer to the data.
|
|
|
|
|
|
|
|
|
|
### `api` Folder
|
2022-01-26 08:12:22 +00:00
|
|
|
|
* We like to place all our API components into a package within an app called
|
2023-11-26 10:54:19 +00:00
|
|
|
|
`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
|
2022-01-26 08:12:22 +00:00
|
|
|
|
we were to put it in the root of our app, then we would end up with a huge list
|
2023-11-26 10:54:19 +00:00
|
|
|
|
of API-specific modules in the general area of the app. That's without getting
|
|
|
|
|
into the mess of API versioning.
|
2022-01-26 08:12:22 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2023-11-26 10:54:19 +00:00
|
|
|
|
|
|
|
|
|
#### API Versioning
|
|
|
|
|
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.
|
2022-04-14 13:50:07 +01:00
|
|
|
|
|
|
|
|
|
For different API versions, we're assuming the following will change:
|
2023-11-26 10:54:19 +00:00
|
|
|
|
- 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.
|
2022-04-14 13:50:07 +01:00
|
|
|
|
|
2023-11-26 10:54:19 +00:00
|
|
|
|
Sufficient unit tests and integration tests should wrap services and API
|
|
|
|
|
endpoints to ensure full compatibility.
|
2022-01-25 03:15:53 +00:00
|
|
|
|
|
2022-04-14 13:57:18 +01:00
|
|
|
|
|
2023-11-26 10:54:19 +00:00
|
|
|
|
#### What's `v2` of an API?
|
2024-11-05 09:12:04 +00:00
|
|
|
|
Currently, we're proposing that major changes to the following constitutes a new
|
|
|
|
|
API version:
|
2022-04-14 13:57:18 +01:00
|
|
|
|
1. Representation of data, either for submission or retrieval
|
2022-08-09 06:04:56 +01:00
|
|
|
|
1. Major optimizations
|
|
|
|
|
1. Major code reorganization and code refactor
|
2023-11-26 10:54:19 +00:00
|
|
|
|
1. Usually, in a Django project, you won't need to worry about API versioning
|
2022-04-14 13:57:18 +01:00
|
|
|
|
|
2023-11-25 17:52:44 +00:00
|
|
|
|
|
2022-01-26 08:04:30 +00:00
|
|
|
|
### `config`
|
|
|
|
|
* Contains project configuration files, including the primary URL file
|
2023-11-26 10:54:19 +00:00
|
|
|
|
* ~~Contains settings split into `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.
|
2022-01-25 03:15:53 +00:00
|
|
|
|
|
2022-01-26 08:04:30 +00:00
|
|
|
|
### `deployments`
|
2023-11-26 10:54:19 +00:00
|
|
|
|
* Contains Docker, Docker-Compose and nginx specific files for deploying in
|
|
|
|
|
different environments.
|
2022-01-26 08:12:22 +00:00
|
|
|
|
|
|
|
|
|
|
2023-11-26 10:54:19 +00:00
|
|
|
|
### Exception handling
|
|
|
|
|
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
|
2022-01-26 08:12:22 +00:00
|
|
|
|
|
|
|
|
|
|
2023-11-26 11:24:25 +00:00
|
|
|
|
## FAQ
|
|
|
|
|
> 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.
|
|
|
|
|
|
|
|
|
|
|
2022-01-25 03:15:53 +00:00
|
|
|
|
## References
|
2022-01-26 08:04:30 +00:00
|
|
|
|
- [Two Scoops of Django by Daniel and Audrey Feldroy](https://www.feldroy.com/books/two-scoops-of-django-3-x)
|
|
|
|
|
- [Django Best Practices](https://django-best-practices.readthedocs.io/en/latest/index.html)
|
|
|
|
|
- [Cookiecutter Django](https://github.com/cookiecutter/cookiecutter-django)
|
|
|
|
|
- [HackSoft Django Style Guide](https://github.com/HackSoftware/Django-Styleguide)
|
|
|
|
|
- [Radoslav Georgiev - Django Structure for Scale and Longevity](https://www.youtube.com/watch?v=yG3ZdxBb1oo)
|
2023-11-26 10:54:19 +00:00
|
|
|
|
- [Build APIs You Won't Hate](https://apisyouwonthate.com/books/build-apis-you-wont-hate/)
|
2023-11-26 10:56:48 +00:00
|
|
|
|
- [Tuxedo Style Guides](https://github.com/saqibur/tuxedo)
|
2024-11-05 08:47:29 +00:00
|
|
|
|
- [Django Anti Patterns](https://www.django-antipatterns.com/)
|