This is a Django project that provides an API for apartment rentals.
It is powered by Django
with Django-Ninja
(instead of the bulky Django REST Framework).
The authentication is handled by django-ninja-jwt
, and as the name suggests, it uses JWT tokens.
The database is PostgreSQL
.
In a hurry? Start the project with docker:
Note: make sure to set the correct permissions on your host machine for the media folder if you want to upload photos.
docker-compose --env-file=.env.docker up
- Python 3.12
- Django 5.0.1
Make sure to have Python 3.12 installed and poetry installed with it.
NOTE: If you are running on a Mac (M1, M2, M3), see below.
run:
poetry install --no-root
If you are running on a Mac (M1, M2, M3), it's recommended to create first a virtual environment specifying the architecture of the Python interpreter:
arch -arm64 python3 -m venv .venv
Then, activate the virtual environment:
source .venv/bin/activate
Finally, install the dependencies:
poetry install --no-root
Note:
- make sure to start postgresql before running the following commands (
docker-compose --env-file=.env.defaults up postgres
) - make sure to move into the
src
directory before running the following commands
There are two utilty scripts to bootstrap the database:
It will run the migrations and create a superuser.
The superuser username and password are loaded from the configuration file.
If not specified, the default username is admin
and the default password is admin
.
A warning will be displayed if the default credentials are used.
It will also create by default a Group named realtor
that will be used for permissions.
2. python manage.py create-fake-data [--apartments <number>] [--users <number>] [--realtors <number>]
It will create fake data for the apartments, users and realtors.
- Every user will have the following email:
user{x}@example.com
, where x is a number starting from 1. - Every realtor will have the following email:
realtor{x}example.com
, where x is a number starting from 1. - Every apartment will have a random realtor assigned to it. Will also have random fake data for the rest of the fields.
Note:
- make sure to start postgresql before running the following commands (
docker-compose --env-file=.env.defaults up postgres
)
To run the server locally, run the following command:
python manage.py runserver
This will load the settings from the .env.defaults
file. If not found, it will attempt to load the settings from:
- the
.env
file. - the
settings.ini
file. - the environment variables.
To specify which settings file to use, set it as an environment variable:
USE_ENV=.env.production python manage.py runserver
The server will be available at http://localhost:8000
.
The API Documentation will be available at http://localhost:8000/api/docs
.
This project has 100% test coverage. To run the tests locally, run the following command:
pytest --cov=. src/tests/ -vv && coverage html
then open the htmlcov/index.html
file in your browser.
This project uses ruff for linting and formatting.
If desired, install the pre-commit hooks:
pre-commit install
If you want to run the linter manually, run:
ruff check . --fix
If you want to run the formatter manually, run:
ruff format .
This is a simple project, therefore due to its scale some shortcuts were taken:
- The buisness logic is in the views. For a bigger project, it would be better to move it to a service layer and create custom exception handlers.
- The object-permissions are hardcoded in the views. For a bigger project, it would be better to move them to a permission layer.
- Each apartment has a single realtor assigned to it. For a bigger project, it would be better to have a many-to-many relationship between apartments and realtors.
- The search functionality is very basic. For a bigger project, it would be better to use a search engine like Meilisearch or Elasticsearch.
- For the sake of simplicity, in the docker image this is deployed with a single gunincorn worker. For a bigger project, it would be better to use multiple workers with a combination of gunicorn and uvicorn, switching from WSGI to ASGI, making the necessary adjustments to the codebase (i.e., using the async ORM and enpoints).