- 공유 링크 만들기
- X
- 이메일
- 기타 앱
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Django 프로젝트 구조 이렇게 짜면 협업이 편해진다 (서비스 분리 전략)
안녕하세요! 오늘은 Django 프로젝트를 효율적으로 구조화하여 팀 협업을 개선하는 방법에 대해 알아보겠습니다. 잘 구조화된 프로젝트는 유지보수성과 확장성을 높여줍니다.
왜 프로젝트 구조가 중요한가요?
좋은 프로젝트 구조의 이점:
- 유지보수성: 코드를 쉽게 찾고 수정할 수 있습니다.
- 확장성: 새로운 기능을 쉽게 추가할 수 있습니다.
- 재사용성: 코드를 다른 프로젝트에서 재사용할 수 있습니다.
- 테스트 용이성: 단위 테스트와 통합 테스트가 쉬워집니다.
- 협업 효율성: 여러 개발자가 동시에 작업하기 좋습니다.
권장 프로젝트 구조
project/
├── apps/ # 애플리케이션 디렉토리
│ ├── core/ # 핵심 기능
│ ├── users/ # 사용자 관리
│ ├── products/ # 상품 관리
│ └── orders/ # 주문 관리
├── config/ # 프로젝트 설정
│ ├── settings/ # 설정 파일들
│ │ ├── base.py # 기본 설정
│ │ ├── development.py # 개발 환경 설정
│ │ └── production.py # 프로덕션 환경 설정
│ ├── urls.py # URL 설정
│ └── wsgi.py # WSGI 설정
├── docs/ # 문서
├── scripts/ # 유틸리티 스크립트
├── tests/ # 테스트
├── requirements/ # 의존성 관리
│ ├── base.txt # 기본 의존성
│ ├── development.txt # 개발용 의존성
│ └── production.txt # 프로덕션용 의존성
└── manage.py # Django 관리 명령어
애플리케이션 구조
1. Core 앱
# apps/core/models.py
from django.db import models
class TimeStampedModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
# apps/core/managers.py
from django.db import models
class ActiveManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(is_active=True)
2. Users 앱
# apps/users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from core.models import TimeStampedModel
class User(AbstractUser, TimeStampedModel):
email = models.EmailField(unique=True)
phone_number = models.CharField(max_length=15, blank=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
# apps/users/serializers.py
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'email', 'username', 'phone_number']
3. Products 앱
# apps/products/models.py
from django.db import models
from core.models import TimeStampedModel
class Product(TimeStampedModel):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField()
stock = models.IntegerField(default=0)
objects = models.Manager()
active = ActiveManager()
# apps/products/services.py
class ProductService:
@staticmethod
def create_product(data):
# 상품 생성 로직
pass
@staticmethod
def update_stock(product_id, quantity):
# 재고 업데이트 로직
pass
설정 파일 구조
1. 기본 설정 (base.py)
# config/settings/base.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third party apps
'rest_framework',
'corsheaders',
# Local apps
'apps.core',
'apps.users',
'apps.products',
'apps.orders',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
2. 개발 환경 설정 (development.py)
# config/settings/development.py
from .base import *
DEBUG = True
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# 개발용 추가 설정
INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
URL 구조
# config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('apps.users.urls')),
path('api/v1/', include('apps.products.urls')),
path('api/v1/', include('apps.orders.urls')),
]
# apps/users/urls.py
from django.urls import path
from . import views
app_name = 'users'
urlpatterns = [
path('users/', views.UserListView.as_view(), name='user-list'),
path('users/<int:pk>/', views.UserDetailView.as_view(), name='user-detail'),
]
서비스 계층 구조
1. 서비스 클래스
# apps/orders/services.py
from django.db import transaction
from .models import Order, OrderItem
class OrderService:
@staticmethod
@transaction.atomic
def create_order(user, items):
order = Order.objects.create(user=user)
for item in items:
OrderItem.objects.create(
order=order,
product=item['product'],
quantity=item['quantity']
)
return order
@staticmethod
def cancel_order(order_id):
order = Order.objects.get(id=order_id)
order.status = 'cancelled'
order.save()
return order
2. 뷰에서 서비스 사용
# apps/orders/views.py
from rest_framework import viewsets
from .models import Order
from .serializers import OrderSerializer
from .services import OrderService
class OrderViewSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
def perform_create(self, serializer):
items = self.request.data.get('items', [])
order = OrderService.create_order(self.request.user, items)
serializer.instance = order
테스트 구조
# tests/test_orders.py
from django.test import TestCase
from apps.orders.services import OrderService
from apps.products.models import Product
from apps.users.models import User
class OrderServiceTest(TestCase):
def setUp(self):
self.user = User.objects.create_user(
email='test@example.com',
password='testpass123'
)
self.product = Product.objects.create(
name='Test Product',
price=1000
)
def test_create_order(self):
items = [{'product': self.product, 'quantity': 2}]
order = OrderService.create_order(self.user, items)
self.assertEqual(order.user, self.user)
self.assertEqual(order.items.count(), 1)
문서화
1. API 문서
# apps/orders/schemas.py
from drf_yasg import openapi
order_schema = {
'operation_description': '주문 생성 API',
'manual_parameters': [
openapi.Parameter(
'items',
openapi.IN_BODY,
description='주문 상품 목록',
type=openapi.TYPE_ARRAY,
items=openapi.Items(
type=openapi.TYPE_OBJECT,
properties={
'product_id': openapi.Schema(type=openapi.TYPE_INTEGER),
'quantity': openapi.Schema(type=openapi.TYPE_INTEGER),
}
)
),
],
'responses': {
201: openapi.Response(
description='주문 생성 성공',
schema=OrderSerializer
),
}
}
협업을 위한 추가 팁
- 코드 스타일 가이드: black, isort, flake8 등의 도구 사용
- Git 전략: Git Flow 또는 Trunk Based Development 채택
- 리뷰 프로세스: Pull Request 템플릿과 리뷰 체크리스트 사용
- CI/CD: GitHub Actions 또는 GitLab CI 설정
- 문서화: README.md와 API 문서 꾸준히 업데이트
결론
잘 구조화된 Django 프로젝트는 팀의 생산성을 크게 향상시킵니다. 이 글에서 소개한 구조와 패턴들을 참고하여 자신의 팀에 맞는 프로젝트 구조를 설계해보세요. 추가적인 질문이나 궁금한 점이 있으시면 댓글로 남겨주세요!
댓글
댓글 쓰기