Thanks to visit codestin.com
Credit goes to github.com

Skip to content

2044smile/shipment

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

shipment

  • ํšŒ์› ์„œ๋น„์Šค ๊ตฌํ˜„ ์™„๋ฃŒ
    • ์นด์นด์˜ค ๋กœ๊ทธ์ธ djangorestframework-simplejwt ์ด์šฉํ•˜์—ฌ ์•ก์„ธ์Šค ํ† ํฐ ๊ด€๋ฆฌ
  • ๋ฐฐ์†ก ์„œ๋น„์Šค ๊ตฌํ˜„ ์™„๋ฃŒ
    • docker-compose (django, rabbitmq, celery)
    • ๋ฐฐ์†ก ์ถœ๋ฐœ โžก Rabbitmq(broker) + Celery(worker) ๋น„๋™๊ธฐ 300์ดˆ ์ง€์—ฐ ์‹œ๊ฐ„ โžก ๋ฐฐ์†ก ๋„์ฐฉ
  • ์•„์ดํ…œ ์„œ๋น„์Šค ๊ตฌํ˜„ ์™„๋ฃŒ
  • ์ฃผ๋ฌธ ์„œ๋น„์Šค ๊ตฌํ˜„ ์™„๋ฃŒ

Installed

  • django==4.2.11 # stable version
  • djangorestframework
  • djangorestframework-simplejwt
  • drf-yasg

Docker-compose

  • Django
  • rabbitmq
  • celery

Middleware

  • GET /health/ # ok

Feature

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

API

Account

  • [POST] accounts/signup
  • [POST] accounts/signin
  • [POST] accounts/token/verify
  • [POST] accounts/token/refresh

Deliveries

  • [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

Items

  • [GET] /deliveries/ list
  • [POST] /deliveries/ create
  • [GET] /deliveries/{id}/ read
  • [PUT] /deliveries/{id}/ update
  • [PATCH] /deliveries/{id}/ partial update
  • [DELETE] /deliveries/{id}/ delete

Orders

  • [GET] /deliveries/ list
  • [POST] /deliveries/ create
  • [GET] /deliveries/{id}/ read
  • [PUT] /deliveries/{id}/ update
  • [PATCH] /deliveries/{id}/ partial update
  • [DELETE] /deliveries/{id}/ delete

TIP

  • ๋”•์…”๋„ˆ๋ฆฌ ์ปดํ”„๋ฆฌํ—จ์…˜
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'})

Reference

์‹œ๋‚˜๋ฆฌ์˜ค

1. ์นด์นด์˜ค ๋กœ๊ทธ์ธ ํ”„๋ก ํŠธ์—”๋“œ & ํšŒ์› ์ •๋ณด

alt text

  1. Postman - Authorization Client ID, Callback URL, ... ์„ค์ • ํ›„ - Get New Access Token
  2. ์นด์นด์˜ค ๋กœ๊ทธ์ธ์ฐฝ - ํšŒ์›๊ฐ€์ž…/๋กœ๊ทธ์ธ - ์นด์นด์˜ค ํ† ํฐ ๋ฐœ๊ธ‰
  3. ์นด์นด์˜ค ํ† ํฐ์œผ๋กœ ํšŒ์›์ •๋ณด ํ™•์ธ ๊ฐ€๋Šฅ

2. ํšŒ์›๊ฐ€์ž…/๋กœ๊ทธ์ธ ๋ฐฑ์—”๋“œ

alt text

  1. ์นด์นด์˜ค ํ† ํฐ์œผ๋กœ ํšŒ์›๊ฐ€์ž…/๋กœ๊ทธ์ธ ํ† ํฐ ๋ฐœ๊ธ‰ access_token
  2. access_token ์œผ๋กœ shipment ์„œ๋น„์Šค ์ด์šฉ ๊ฐ€๋Šฅ
  3. Swagger - Authorize - Bearer eyJhbGciOiJIUzI1NiIsI...

3. ์•„์ดํ…œ(์ œํ’ˆ) ์ƒ์„ฑ POST /items/

  1. ํ† ํฐ๊ณผ ํ•จ๊ป˜ ํŒ๋งคํ•  ์•„์ดํ…œ์„ ์ƒ์„ฑ
{
    "id": 2,
    "user": 1,
    "name": "๋ฐ˜ํฌ์ž์ด",
    "description": "",
    "price": 20000000000
}

4. ์•„์ดํ…œ(๋ฆฌ์ŠคํŠธ) - GET /items/

  1. ํ† ํฐ์œผ๋กœ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋„ ํŒ๋งค ๋“ฑ๋กํ•œ ์•„์ดํ…œ ์กฐํšŒ
[
    {
        "id": 1,
        "user": 2,
        "name": "๋ฆฌ๋”์Šค๋นŒ",
        "description": "",
        "price": 175000000
    },
    {
        "id": 2,
        "user": 1,
        "name": "๋ฐ˜ํฌ์ž์ด",
        "description": "",
        "price": 20000000000
    }
]

5. ์•„์ดํ…œ ์ฃผ๋ฌธ - /orders/

  1. ์ƒ๋Œ€๋ฐฉ์˜ ์•„์ดํ…œ ID ๋ฅผ ์ž…๋ ฅ
{
    "user":2,
    "item":1,
    "purchase_date":"2024-12-04T12:47:40.641913Z"
}

6. ๋ฐฐ์†ก ์„œ๋น„์Šค ์ ‘์ˆ˜ - POST /deliveries/

  1. ํ† ํฐ์œผ๋กœ API ๋ฅผ ์ด์šฉํ•˜๋Š” ์‚ฌ๋žŒ์€ ํŒ๋งค์ž
  2. order ์ •๋ณด์— ํŒ๋งค์ž, ๊ตฌ๋งค์ž ์ •๋ณด๊ฐ€ ์กด์žฌ
{
  "order": 1,
  "address": "์„œ์ดˆ๊ตฌ ๋ฐ˜ํฌ๋™",
  "status": "0"  // pending
}
// response
{
  "id": 3,
  "order": 1,
  "sender": 1,
  "receiver": 2,
  "address": "์„œ์ดˆ๊ตฌ ๋ฐ˜๋™",
  "status": "0"
}

7. ๋ฐฐ์†ก ์„œ๋น„์Šค ์ถœ๋ฐœ/๋„์ฐฉ - GET /deliveries/{id}/departure/

  1. Delivery ID ์ž…๋ ฅ
{
    "id": 3
}
// response
{
  "message": "3408007879 ๊ณ ๊ฐ๋‹˜์˜ ์ƒํ’ˆ ๋ฐ˜ํฌ์ž์ด ๋ฐฐ์†ก์ด ์ถœ๋ฐœํ•˜์˜€์Šต๋‹ˆ๋‹ค. the delivery service will arrive in 60 seconds"
}

alt text

About

python, django, rabbitmq, celery, drf, drf-simplejwt, swagger

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published