- ํ์ ์๋น์ค ๊ตฌํ ์๋ฃ
- ์นด์นด์ค ๋ก๊ทธ์ธ djangorestframework-simplejwt ์ด์ฉํ์ฌ ์ก์ธ์ค ํ ํฐ ๊ด๋ฆฌ
- ๋ฐฐ์ก ์๋น์ค ๊ตฌํ ์๋ฃ
- docker-compose (django, rabbitmq, celery)
- ๋ฐฐ์ก ์ถ๋ฐ โก Rabbitmq(broker) + Celery(worker) ๋น๋๊ธฐ 300์ด ์ง์ฐ ์๊ฐ โก ๋ฐฐ์ก ๋์ฐฉ
- ์์ดํ ์๋น์ค ๊ตฌํ ์๋ฃ
- ์ฃผ๋ฌธ ์๋น์ค ๊ตฌํ ์๋ฃ
- django==4.2.11
# stable version - djangorestframework
- djangorestframework-simplejwt
- drf-yasg
- Django
- rabbitmq
- celery
- GET /health/
# ok
1. UserModel Kakao signin, signup
2. docker-compose (django, rabbitmq, celery)
3. I used Swagger(drf-yasg)
4. simplejwt using bearer JWT token
5. TestCode
- [POST] accounts/signup
- [POST] accounts/signin
- [POST] accounts/token/verify
- [POST] accounts/token/refresh
- [GET] /deliveries/ list
- [POST] /deliveries/ create
- [GET] /deliveries/{id}/ read
- [PUT] /deliveries/{id}/ update
- [PATCH] /deliveries/{id}/ partial update
- [DELETE] /deliveries/{id}/ delete
- [GET] /deliveries/{id}/departure departure โก arrival
- [GET] /deliveries/ list
- [POST] /deliveries/ create
- [GET] /deliveries/{id}/ read
- [PUT] /deliveries/{id}/ update
- [PATCH] /deliveries/{id}/ partial update
- [DELETE] /deliveries/{id}/ delete
- [GET] /deliveries/ list
- [POST] /deliveries/ create
- [GET] /deliveries/{id}/ read
- [PUT] /deliveries/{id}/ update
- [PATCH] /deliveries/{id}/ partial update
- [DELETE] /deliveries/{id}/ delete
- ๋์ ๋๋ฆฌ ์ปดํ๋ฆฌํจ์
class OrderSerializer(serializers.ModelSerializer):
items_details = serializers.SerializerMethodField()
class Meta:
model = Order
fields = ['user', 'items_details']
def get_items_details(self, obj):
return {item.id: item.name for item in obj.items.all()}- get_random_string ๋๋ค ๋ฌธ์์ด
from django.utils.crypto import get_random_string
target = get_random_string(length=16, allowed_chars="๊ฐ๋๋ค๋ผ๋ง๋ฐ์ฌthankyousomuch")- Swagger details
access_token = openapi.Parameter('access_token', openapi.IN_QUERY, description="Send it to me from Frontend", required=True, type=openapi.TYPE_STRING)
@swagger_auto_schema(operation_description="ํ๋ก ํธ์๋(POSTMAN) ํ ํฐ ์ ๋ฌ", responses={200: 'Success'}, manual_parameters=[access_token])- custom middleware
from django.http import JsonResponse
class HealthCheckMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.path == '/health/' or request.path == '/health':
return JsonResponse({"status": "ok"}, status=200)
return self.get_response(request)- Celery all flow
# config/settings.py
INSTALLED_APPS = ['celery',]
CELERY_TIMEZONE = TIME_ZONE
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
# CELERY_BROKER_URL = os.environ.get("CELERY_BROKER", "redis://redis:6379/0")
# CELERY_RESULT_BACKEND = os.environ.get("CELERY_BACKEND", "redis://redis:6379/0")
CELERY_BROKER_URL="amqp://guest:guest@rabbitmq:5672//"
# CELERY_RESULT_BACKEND = 'django-db'
# config/celery.py
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
app = Celery("config")
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
# config/__init__.py
from .celery import app as celery_app
__all__ = ['celery_app']
# app/tasks.py
from config.celery import app
from .models import Delivery
@app.task
def process_delivery_task(delivery_id):
instance = Delivery.objects.get(id=delivery_id)
instance.status = "2" # ๋ฐฐ์ก ์๋ฃ
instance.save()
# app/views.py
class DeliveryViewSet(viewsets.ModelViewSet):
queryset = Delivery.objects.all()
serializer_class = DeliverySerializer
permission_classes = [permissions.IsAuthenticated]
authentication_classes = [JWTAuthentication]
@action(detail=True, methods=['GET'], name='departure')
def departure(self, request, pk=None):
instance = self.get_object()
if instance.status == '2':
return JsonResponse({'message': f'{instance.receiver.kakao_id} ๊ณ ๊ฐ๋์ ์ํ์ ์ด๋ฏธ ๋ฐฐ์ก์ด ์๋ฃ ๋์์ต๋๋ค.'})
instance.status = '1'
instance.save()
process_delivery_task.s(delivery_id=instance.id).apply_async(countdown=60)
return JsonResponse({'message': f'{instance.receiver.kakao_id} ๊ณ ๊ฐ๋์ ์ํ {instance.order.item.name} ๋ฐฐ์ก์ด ์ถ๋ฐํ์์ต๋๋ค. the delivery service will arrive in 60 seconds'})- Postman - Authorization Client ID, Callback URL, ... ์ค์ ํ -
Get New Access Token - ์นด์นด์ค ๋ก๊ทธ์ธ์ฐฝ - ํ์๊ฐ์
/๋ก๊ทธ์ธ -
์นด์นด์ค ํ ํฐ ๋ฐ๊ธ - ์นด์นด์ค ํ ํฐ์ผ๋ก
ํ์์ ๋ณด ํ์ธ ๊ฐ๋ฅ
- ์นด์นด์ค ํ ํฐ์ผ๋ก
ํ์๊ฐ์ /๋ก๊ทธ์ธํ ํฐ ๋ฐ๊ธ access_token - access_token ์ผ๋ก shipment ์๋น์ค ์ด์ฉ ๊ฐ๋ฅ
- Swagger - Authorize - Bearer eyJhbGciOiJIUzI1NiIsI...
- ํ ํฐ๊ณผ ํจ๊ป ํ๋งคํ ์์ดํ ์ ์์ฑ
{
"id": 2,
"user": 1,
"name": "๋ฐํฌ์์ด",
"description": "",
"price": 20000000000
}- ํ ํฐ์ผ๋ก ๋ค๋ฅธ ์ฌ์ฉ์๋ ํ๋งค ๋ฑ๋กํ ์์ดํ ์กฐํ
[
{
"id": 1,
"user": 2,
"name": "๋ฆฌ๋์ค๋น",
"description": "",
"price": 175000000
},
{
"id": 2,
"user": 1,
"name": "๋ฐํฌ์์ด",
"description": "",
"price": 20000000000
}
]- ์๋๋ฐฉ์ ์์ดํ ID ๋ฅผ ์ ๋ ฅ
{
"user":2,
"item":1,
"purchase_date":"2024-12-04T12:47:40.641913Z"
}- ํ ํฐ์ผ๋ก API ๋ฅผ ์ด์ฉํ๋ ์ฌ๋์ ํ๋งค์
- order ์ ๋ณด์ ํ๋งค์, ๊ตฌ๋งค์ ์ ๋ณด๊ฐ ์กด์ฌ
{
"order": 1,
"address": "์์ด๊ตฌ ๋ฐํฌ๋",
"status": "0" // pending
}
// response
{
"id": 3,
"order": 1,
"sender": 1,
"receiver": 2,
"address": "์์ด๊ตฌ ๋ฐ๋",
"status": "0"
}- Delivery ID ์ ๋ ฅ
{
"id": 3
}
// response
{
"message": "3408007879 ๊ณ ๊ฐ๋์ ์ํ ๋ฐํฌ์์ด ๋ฐฐ์ก์ด ์ถ๋ฐํ์์ต๋๋ค. the delivery service will arrive in 60 seconds"
}