Django Rest Api
Playground API Backend using Django
How to Start Django Project
1. Install Django
- create virtualenv
use pyenv
pyenv virtualenv <project-name>
pyenv activate <project-name>
or python venv on windows
python -m venv .venv
.venv\Scripts\activate
- install django, start the project and upgrade lastest pip
pip install --upgrade pip
pip install django==4.2.16
pip freeze
django-admin startproject <project-name>
2. Prepare Starter
- enter to project directory
cd <project-name>
- create starter files
touch .env .env.example .gitignore README.md requirements.txt
- add package version to
requirements.txt
Django==4.2.16
3. Init git repository and Install starter package
git init
pip install black django-environ psycopg2-binary
pip freeze
psycopg2-binary
is Postgres lib, adjust this package if use other database engine
- add package version to
requirements.txt
black==24.10.0
django-environ==0.11.2
psycopg2-binary==2.9.10
4. Setup env variable and prepare database
- create database on posgres
- add env config starter
.env
and.env.example
DEBUG=True
SECRET_KEY=your-secret-key
ALLOWED_HOSTS=*
DATABASE_URL=psql://postgresuser:postgrespass@127.0.0.1:5432/postgresdb
# DATABASE_URL=sqlite://../db.sqlite3
STATIC_DIR=static
MEDIA_DIR=media
DJANGO_SUPERUSER_USERNAME=karamel
DJANGO_SUPERUSER_EMAIL=admin@karamel.id
DJANGO_SUPERUSER_PASSWORD=karameladmin12345
- setting env variable on
<project-name>/settings.py
import environ
import os
# Django-environ
env = environ.Env(DEBUG=(bool, False))
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Take environment variables from .env file
environ.Env.read_env(os.path.join(BASE_DIR, ".env"))
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env("DEBUG")
ALLOWED_HOSTS = env("ALLOWED_HOSTS").split(",")
# ...
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {"default": env.db()}
# ...
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "/static/"
STATIC_ROOT = env("STATIC_DIR")
MEDIA_URL = "/media/"
MEDIA_ROOT = env("MEDIA_DIR")
# ...
5. Setup default User Model
- create django apps member for manage user data
python manage.py startapp member
- create model
User
onmember/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
- setting variable on
<project-name>/settings.py
INSTALLED_APPS = [
# ...
# apps
"member.apps.MemberConfig",
]
# ...
AUTH_USER_MODEL = "member.User"
- create generate superuser on command
member/management/commands/generate_superuser.py
import os
from django.core.management.base import BaseCommand
from django.core.management import call_command
from member.models import User
class Command(BaseCommand):
help = "Generate Superuser"
def handle(self, *args, **options):
username = os.environ.get("DJANGO_SUPERUSER_USERNAME", None)
email = os.environ.get("DJANGO_SUPERUSER_EMAIL", None)
is_admin_exists = User.objects.filter(
username=username, email=email, is_superuser=True
).exists()
if not is_admin_exists:
call_command("createsuperuser", "--noinput")
6. Running
python manage.py makemigrations
python manage.py migrate
python manage.py generate_superuser
python manage.py runserver
Setup Django Package
Rest Framework, corsheader, swagger, Rest Auth, Allauth, Simple JWT
1. Install Package
pip install djangorestframework drf_yasg django-filter django-cors-headers dj-rest-auth 'django-allauth[socialaccount]' djangorestframework-simplejwt
pip freeze
- add package version to
requirements.txt
django-cors-headers==4.6.0
django-filter==24.3
djangorestframework==3.15.2
drf-yasg==1.21.8
dj-rest-auth==7.0.0
django-allauth[socialaccount]==65.2.0
djangorestframework-simplejwt==5.3.1
2. Setup settings.py
- add configuration variable on
<project-name>/settings.py
from datetime import timedelta
INSTALLED_APPS = [
# ...
# libs
"corsheaders",
"rest_framework",
"rest_framework_simplejwt.token_blacklist",
"drf_yasg",
"dj_rest_auth",
"allauth",
"allauth.account",
"allauth.socialaccount",
"dj_rest_auth.registration",
]
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
# ...
"allauth.account.middleware.AccountMiddleware",
]
# ...
# corsheaders
CORS_ALLOW_ALL_ORIGINS = True
# DRF
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}
# swagger
SWAGGER_SETTINGS = {
"SECURITY_DEFINITIONS": {
"Bearer": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
},
},
}
# dj-rest-auth
REST_USE_JWT = True
REST_AUTH = {
"USE_JWT": True,
"TOKEN_MODEL": None,
"JWT_AUTH_HTTPONLY": False,
"JWT_AUTH_RETURN_EXPIRATION": True,
"USER_DETAILS_SERIALIZER": "api.auth.serializers.UserDetailsSerializer",
}
# allauth
ACCOUNT_AUTHENTICATION_METHOD = "username_email"
ACCOUNT_EMAIL_VERIFICATION = "none"
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
)
# simplejwt
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"AUTH_HEADER_TYPES": ("Bearer",),
"ROTATE_REFRESH_TOKENS": True,
"BLACKLIST_AFTER_ROTATION": True,
}
3. Setup Serializers
- create
api/auth/serializers.py
from rest_framework import serializers
from member.models import User
class UserDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
"username",
"email",
"first_name",
"last_name",
)
4. Setup Views
- create
api.auth.views.py
from django.utils.translation import gettext_lazy as _
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from dj_rest_auth.views import LogoutView
from rest_framework.response import Response
from rest_framework import status
class CustomLogoutView(LogoutView):
"""
Calls Django logout method and delete the Token object
assigned to the current User object.
Accepts/Returns nothing.
"""
@swagger_auto_schema(
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
"refresh": openapi.Schema(
type=openapi.TYPE_STRING,
title="Refresh",
description="Logout with blacklist Refresh token",
min_length=1,
)
},
required=["refresh"],
),
)
def post(self, request, *args, **kwargs):
if request.data.get("refresh", None):
return super().post(request, *args, **kwargs)
return Response(
{"detail": _("Refresh token was not included in request data.")},
status=status.HTTP_400_BAD_REQUEST,
)
5. Setup Urls
- add urlpatterns on
<project-name>/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("api.urls")),
]
- create file
api/urls.py
from django.urls import path, re_path, include
from django.conf import settings
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from drf_yasg.generators import OpenAPISchemaGenerator
from api.auth.views import CustomLogoutView
class BothHttpAndHttpsSchemaGenerator(OpenAPISchemaGenerator):
def get_schema(self, request=None, public=False):
schema = super(BothHttpAndHttpsSchemaGenerator, self).get_schema()
schema.schemes = ["http", "https"]
return schema
schema_view = get_schema_view(
openapi.Info(
title="PLAYGROUND API",
default_version="v1",
description="PLAYGROUND Swagger docs",
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
generator_class=BothHttpAndHttpsSchemaGenerator,
)
urlpatterns = [
path("auth/logout/", CustomLogoutView.as_view(), name="rest_logout"),
path("auth/", include("dj_rest_auth.urls")),
path("auth/registration/", include("dj_rest_auth.registration.urls")),
]
if settings.DEBUG:
urlpatterns += [
# Documentation Route
re_path(
r"^swagger(?P<format>\.json|\.yaml)$",
schema_view.without_ui(cache_timeout=0),
name="schema-json",
),
re_path(
r"^docs/$",
schema_view.with_ui("swagger", cache_timeout=0),
name="schema-swagger-ui",
),
re_path(
r"^redoc/$",
schema_view.with_ui("redoc", cache_timeout=0),
name="schema-redoc",
),
]
Let's go to Project Structure
Example goods
apps with model Category
, Product
and ProductVarian
1. Create app and model
python manage.py startapp goods
- setting variable on
<project-name>/settings.py
INSTALLED_APPS = [
# ...
"goods.apps.GoodsConfig",
]
- create model
Category
,Product
andProductVarian
ongoods/models.py
example - create
admin.register
ongoods/admin.py
example
python manage.py makemigrations
python manage.py migrate
2. Create simple endpoint with urls, views, and serializers
- create dir
api/category
,api/product
,api/variant
- create file
urls.py
,views.py
andserializers.py
on each dir - add urlpatterns on
api/urls.py
How to Development
- clone project.
git clone <url-repository>
- create virtualenv
- copy
.env.example
and rename to.env
file - install
requirements.txt
pip install -r requirements.txt
Table of Contents
- How to Start Django Project
- 1. Install Django
- 2. Prepare Starter
- 3. Init git repository and Install starter package
- 4. Setup env variable and prepare database
- 5. Setup default User Model
- 6. Running
- Setup Django Package
- 1. Install Package
- 2. Setup settings.py
- 3. Setup Serializers
- 4. Setup Views
- 5. Setup Urls
- Let's go to Project Structure
- 1. Create app and model
- 2. Create simple endpoint with urls, views, and serializers
- How to Development