Django 프로젝트 Autobiography 단계별 가이드(도커 적용까지)
사전 준비
목표: 개발 환경 점검
실행
python3 --version
docker --version
docker compose version
확인: 버전이 정상 출력되면 통과.
1. 프로젝트 생성(가상환경 포함)
목표: Django 기반 뼈대 마련
실행
# 새 디렉터리
mkdir autobiography && cd autobiography
# 가상환경
python3 -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
# 장고 설치 및 프로젝트/앱 생성
pip install "Django>=5.0,<6.0" gunicorn
django-admin startproject config .
python manage.py startapp autobiography
확인
python manage.py runserver
브라우저에서 http://127.0.0.1:8000 확인.
2. 최소 도메인 모델 설계
목표: 자서전(Autobiography)용 핵심 엔티티 정의
실행: autobiography/models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
birth_year = models.IntegerField(null=True, blank=True)
bio = models.TextField(blank=True)
def __str__(self): return self.name
class Chapter(models.Model):
title = models.CharField(max_length=200)
order = models.PositiveIntegerField(default=1)
summary = models.TextField(blank=True)
def __str__(self): return f"{self.order}. {self.title}"
class Meta: ordering = ["order"]
class Entry(models.Model):
chapter = models.ForeignKey(Chapter, on_delete=models.CASCADE, related_name="entries")
date = models.DateField(null=True, blank=True)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self): return f"Entry for {self.chapter.title}"
config/settings.py의 INSTALLED_APPS에 'autobiography' 추가 후:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
확인: python manage.py runserver → /admin 에서 Author/Chapter/Entry 등록 가능.:
관리자 표시: autobiography/admin.py
from django.contrib import admin
from .models import Author, Chapter, Entry
admin.site.register([Author, Chapter, Entry])
3. 최소 페이지(View/URL/Template)
목표: 독자가 장/에피소드를 열람
실행
- autobiography/views.py
from django.views.generic import ListView, DetailView
from .models import Chapter, Entry
class ChapterListView(ListView):
model = Chapter
template_name = "autobiography/chapter_list.html"
class ChapterDetailView(DetailView):
model = Chapter
template_name = "autobiography/chapter_detail.html"
- config/urls.py
from django.contrib import admin
from django.urls import path
from autobiography.views import ChapterListView, ChapterDetailView
urlpatterns = [
path("admin/", admin.site.urls),
path("", ChapterListView.as_view(), name="chapter_list"),
path("chapters/<int:pk>/", ChapterDetailView.as_view(), name="chapter_detail"),
]
- 템플릿(예시)
- templates/autobiography/chapter_list.html
- <h1>Autobiography</h1> <ul> {% for ch in object_list %} <li><a href="{% url 'chapter_detail' ch.pk %}">{{ ch.order }}. {{ ch.title }}</a></li> {% empty %}<li>아직 장이 없습니다.</li>{% endfor %} </ul>
- templates/autobiography/chapter_detail.html
- <h2>{{ object.order }}. {{ object.title }}</h2> <p>{{ object.summary }}</p> <hr> {% for e in object.entries.all %} <article> <small>{{ e.date }} · {{ e.created_at|date:"Y-m-d H:i" }}</small> <p style="white-space:pre-wrap">{{ e.content }}</p> </article> <hr> {% empty %}에피소드가 없습니다.{% endfor %}
확인: 루트 페이지에서 장 목록/상세가 보이면 통과.
4. 환경변수/정적파일 설정
목표: 도커화를 위한 설정 분리
실행: config/settings.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "unsafe-dev")
DEBUG = os.environ.get("DJANGO_DEBUG", "1") == "1"
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "*").split(",")
STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
루트에 .env.dev:
DJANGO_SECRET_KEY=change_me_dev
DJANGO_DEBUG=1
DJANGO_ALLOWED_HOSTS=*
확인
python manage.py collectstatic --noinput
staticfiles/가 생성되면 통과.
5. 의존성 고정
목표: 재현 가능한 빌드
실행
pip freeze > requirements.txt
확인: requirements.txt 생성 확인.
6. 도커화(Dockerfile, .dockerignore, EntryPoint)
목표: 컨테이너로 실행 가능한 이미지 만들기
- .dockerignore
.git
__pycache__/
*.pyc
*.log
venv/
.env*
media/
staticfiles/
- Dockerfile
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential pkg-config && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# 비루트 사용자
RUN useradd -m appuser
USER appuser
EXPOSE 8000
# 엔트리포인트(정적수집/마이그레이션/서버)
CMD python manage.py collectstatic --noinput && \
python manage.py migrate --noinput && \
gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 3
확인(빌드/실행)
# 프로젝트 루트에서
docker build -t autobiography:dev .
docker run -d --name autobiography \
--env-file .env.dev -p 8000:8000 autobiography:dev
docker logs -f autobiography
브라우저에서 http://localhost:8000 정상 확인.
권한 오류 발생 시
sudo usermod -aG docker $USER && newgrp docker 후 재시도.
ALLOWED_HOSTS 에러 시 .env.dev에 실제 접근 IP/도메인 추가.
7. Docker Compose(선택, 개발 편의)
목표: 한 줄로 올리고 내리기
루트에 compose.yml:
services:
web:
build: .
image: autobiography:dev
env_file: .env.dev
ports: ["8000:8000"]
volumes:
- .:/app:delegated
- static_volume:/app/staticfiles
restart: unless-stopped
volumes:
static_volume:
실행/확인
docker compose up -d --build
docker compose logs -f web
docker compose down
8. MySQL로 확장(선택)
목표: 운영형 DB 학습
config/settings.py에 조건부 DB 설정 추가:
if os.environ.get("DB_HOST"):
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": os.environ.get("DB_NAME"),
"USER": os.environ.get("DB_USER"),
"PASSWORD": os.environ.get("DB_PASSWORD"),
"HOST": os.environ.get("DB_HOST"),
"PORT": os.environ.get("DB_PORT", "3306"),
"OPTIONS": {"charset": "utf8mb4"},
}
}
.env.mysql
DJANGO_SECRET_KEY=change_me_dev
DJANGO_DEBUG=1
DJANGO_ALLOWED_HOSTS=*
DB_NAME=autobio
DB_USER=autobio
DB_PASSWORD=autobiopw
DB_HOST=db
DB_PORT=3306
compose.mysql.yml
services:
web:
build: .
image: autobiography:mysql-dev
env_file: .env.mysql
depends_on: [db]
ports: ["8000:8000"]
volumes:
- .:/app:delegated
- static_volume:/app/staticfiles
restart: unless-stopped
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: rootpw
TZ: Asia/Seoul
command: ["--character-set-server=utf8mb4","--collation-server=utf8mb4_unicode_ci"]
volumes: [ "db_data:/var/lib/mysql" ]
ports: ["3307:3306"]
volumes:
db_data:
static_volume:
실행/확인
docker compose -f compose.mysql.yml up -d --build
docker compose -f compose.mysql.yml exec web python manage.py migrate
docker compose -f compose.mysql.yml exec web python manage.py createsuperuser
9. Docker Hub 배포(선택)
목표: 이미지 공유/배포
실행
docker login
docker tag autobiography:dev esyfly/autobiography:dev-1
docker push esyfly/autobiography:dev-1
다른 서버:
docker pull esyfly/autobiography:dev-1
docker run -d --name autobiography -p 8000:8000 --env-file .env.dev esyfly/autobiography:dev-1
10. 학습 점검표(스스로 평가)
- 관리자에서 Author/Chapter/Entry를 만들 수 있는가
- 루트 페이지에서 장 목록/상세가 보이는가
- 로컬에서 도커 이미지 빌드/실행이 되는가
- Compose로 올리고 내릴 수 있는가
- MySQL로 전환 후 이민(마이그레이션)과 접속이 되는가
- ALLOWED_HOSTS, 정적파일(collectstatic), 권한 이슈를 스스로 해결할 수 있는가
11. 자주 겪는 오류와 빠른 해결
- docker.sock 권한: sudo usermod -aG docker $USER && newgrp docker
- pip/venv 권한: venv 작업에 sudo 금지, 문제 시 rm -rf venv 후 재생성
- 정적파일 미표시: STATIC_ROOT 설정 + collectstatic 실행 여부 확인
- DB 연결 실패: Compose 내부 접속은 DB_HOST=db(서비스명) 사용
- Gunicorn 경로 오류: gunicorn config.wsgi:application에서 config는 프로젝트 모듈명과 일치해야 함
마무리
위 과정을 완료하면 문학적 자서전 프로젝트(Autobiography)의 최소 기능이 동작하고, 도커 이미지로 실행/배포할 수 있습니다.
'십대를 위한 코딩' 카테고리의 다른 글
Docker Hub의 주요 구성 요소 (0) | 2025.08.21 |
---|---|
도커 기초 개념 정리 (0) | 2025.08.20 |
리눅스에서 도커(Docker) 설치하기 (1) | 2025.08.19 |
[스크리브너] 책 제작 도구, 스크리브너 구성 (0) | 2025.01.27 |
파이썬 개요 (1) | 2024.12.24 |