본문 바로가기
Dev/PyQt

제로에서 시작하는 CS

by wenect 2025. 6. 20.

기획->개발->운영

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. 1주차: Django 기본 개념, 프로젝트 생성, 간단한 뷰/템플릿
  2. 2주차: 모델 정의, 데이터베이스 연동, Admin 사용
  3. 3주차: 폼 처리, 사용자 인증, Bootstrap 적용
  4. 4주차: 고급 기능 (필터링, 페이징, 파일 업로드)
  5. 5주차: 실제 CS 사이트 기능 구현

추가 학습 자료

다음 단계

각 단계를 차례로 따라하면서 CS 사이트의 각 기능을 하나씩 구현

'Dev > PyQt' 카테고리의 다른 글

QAction  (0) 2024.08.11

댓글