기획->개발->운영
Django 기초 학습 가이드
1. 환경 설정
가상환경 생성 및 활성화
# 가상환경 생성
python -m venv venv
# 활성화 (Windows)
venv\Scripts\activate
# 활성화 (Mac/Linux)
source venv/bin/activate
패키지 설치
pip install -r requirements.txt
2. Django 프로젝트 시작
프로젝트 생성
# CS 사이트 프로젝트 생성
django-admin startproject cs_site
cd cs_site
# 앱 생성 (기능별로 나누기)
python manage.py startapp dashboard
python manage.py startapp tickets
python manage.py startapp customers
python manage.py startapp knowledge_base
프로젝트 구조
cs_site/
├── cs_site/ # 프로젝트 설정
│ ├── settings.py # 설정 파일
│ ├── urls.py # URL 라우팅
│ └── wsgi.py
├── dashboard/ # 대시보드 앱
├── tickets/ # 티켓 관리 앱
├── customers/ # 고객 관리 앱
├── knowledge_base/ # 지식베이스 앱
└── manage.py
3. 핵심 개념 이해
MVT 패턴
- Model: 데이터베이스 구조 정의
- View: 비즈니스 로직 처리
- Template: HTML 화면 구성
URL 라우팅
# cs_site/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('dashboard.urls')),
path('tickets/', include('tickets.urls')),
path('customers/', include('customers.urls')),
]
4. 모델 정의 (데이터베이스)
기본 모델 예시
# tickets/models.py
from django.db import models
from django.contrib.auth.models import User
class Ticket(models.Model):
PRIORITY_CHOICES = [
('low', '낮음'),
('medium', '보통'),
('high', '높음'),
('urgent', '긴급'),
]
STATUS_CHOICES = [
('open', '열림'),
('in_progress', '진행중'),
('resolved', '해결됨'),
('closed', '닫힘'),
]
title = models.CharField(max_length=200, verbose_name='제목')
description = models.TextField(verbose_name='내용')
priority = models.CharField(max_length=10, choices=PRIORITY_CHOICES, default='medium')
status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='open')
customer = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='고객')
assigned_to = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True,
related_name='assigned_tickets', verbose_name='담당자')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='생성일')
updated_at = models.DateTimeField(auto_now=True, verbose_name='수정일')
class Meta:
verbose_name = '티켓'
verbose_name_plural = '티켓 목록'
ordering = ['-created_at']
def __str__(self):
return self.title
마이그레이션
# 마이그레이션 파일 생성
python manage.py makemigrations
# 데이터베이스에 적용
python manage.py migrate
# 슈퍼유저 생성
python manage.py createsuperuser
5. 뷰 작성 (비즈니스 로직)
함수 기반 뷰
# tickets/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from .models import Ticket
from .forms import TicketForm
@login_required
def ticket_list(request):
tickets = Ticket.objects.all()
return render(request, 'tickets/list.html', {'tickets': tickets})
@login_required
def ticket_detail(request, ticket_id):
ticket = get_object_or_404(Ticket, id=ticket_id)
return render(request, 'tickets/detail.html', {'ticket': ticket})
@login_required
def ticket_create(request):
if request.method == 'POST':
form = TicketForm(request.POST)
if form.is_valid():
ticket = form.save(commit=False)
ticket.customer = request.user
ticket.save()
return redirect('ticket_detail', ticket_id=ticket.id)
else:
form = TicketForm()
return render(request, 'tickets/create.html', {'form': form})
클래스 기반 뷰 (더 고급)
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
class TicketListView(LoginRequiredMixin, ListView):
model = Ticket
template_name = 'tickets/list.html'
context_object_name = 'tickets'
paginate_by = 10
6. 폼 작성
# tickets/forms.py
from django import forms
from .models import Ticket
class TicketForm(forms.ModelForm):
class Meta:
model = Ticket
fields = ['title', 'description', 'priority']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
'priority': forms.Select(attrs={'class': 'form-select'}),
}
7. 템플릿 작성 (HTML)
기본 레이아웃
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}CS 사이트{% endblock %}</title>
{% load django_bootstrap5 %}
{% bootstrap_css %}
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="{% url 'dashboard' %}">CS 사이트</a>
<div class="navbar-nav">
<a class="nav-link" href="{% url 'ticket_list' %}">티켓</a>
<a class="nav-link" href="{% url 'customer_list' %}">고객</a>
</div>
</div>
</nav>
<div class="container mt-4">
{% block content %}
{% endblock %}
</div>
{% bootstrap_javascript %}
</body>
</html>
티켓 목록 페이지
<!-- templates/tickets/list.html -->
{% extends 'base.html' %}
{% load django_bootstrap5 %}
{% block title %}티켓 목록{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>티켓 목록</h2>
<a href="{% url 'ticket_create' %}" class="btn btn-primary">새 티켓</a>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>제목</th>
<th>우선순위</th>
<th>상태</th>
<th>고객</th>
<th>생성일</th>
</tr>
</thead>
<tbody>
{% for ticket in tickets %}
<tr>
<td><a href="{% url 'ticket_detail' ticket.id %}">{{ ticket.title }}</a></td>
<td>
<span class="badge bg-{% if ticket.priority == 'urgent' %}danger{% elif ticket.priority == 'high' %}warning{% else %}secondary{% endif %}">
{{ ticket.get_priority_display }}
</span>
</td>
<td>{{ ticket.get_status_display }}</td>
<td>{{ ticket.customer.username }}</td>
<td>{{ ticket.created_at|date:"Y-m-d H:i" }}</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center">등록된 티켓이 없습니다.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
8. URL 연결
# tickets/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.ticket_list, name='ticket_list'),
path('<int:ticket_id>/', views.ticket_detail, name='ticket_detail'),
path('create/', views.ticket_create, name='ticket_create'),
]
9. 설정 파일 구성
# cs_site/settings.py (주요 부분)
import os
from decouple import config
# 설치된 앱 등록
INSTALLED_APPS = [
'jazzmin', # Django admin 테마 (admin보다 위에)
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 서드파티 앱
'django_bootstrap5',
'crispy_forms',
'crispy_bootstrap5',
'django_tables2',
'django_filters',
'django_extensions',
'debug_toolbar',
# 내 앱들
'dashboard',
'tickets',
'customers',
'knowledge_base',
]
# Crispy Forms 설정
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
# 데이터베이스 설정
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST', default='localhost'),
'PORT': config('DB_PORT', default='5432'),
}
}
# 정적 파일 설정
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# 미디어 파일 설정
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
10. 개발 서버 실행
# 개발 서버 시작
python manage.py runserver
# 브라우저에서 접속
# http://127.0.0.1:8000/
# http://127.0.0.1:8000/admin/
학습 순서 추천
- 1주차: Django 기본 개념, 프로젝트 생성, 간단한 뷰/템플릿
- 2주차: 모델 정의, 데이터베이스 연동, Admin 사용
- 3주차: 폼 처리, 사용자 인증, Bootstrap 적용
- 4주차: 고급 기능 (필터링, 페이징, 파일 업로드)
- 5주차: 실제 CS 사이트 기능 구현
추가 학습 자료
- Django 공식 문서: https://docs.djangoproject.com/
- Django Girls 튜토리얼: https://tutorial.djangogirls.org/
- MDN Django 튜토리얼: https://developer.mozilla.org/ko/docs/Learn/Server-side/Django
다음 단계
각 단계를 차례로 따라하면서 CS 사이트의 각 기능을 하나씩 구현
댓글