본문 바로가기
Python/Django

Django 워크플로우 정리 (CRUD, 로그인 기능까지)

by 좌우지간에 2025. 1. 8.

📌 Django 워크플로우: (CRUD 기능과 로그인 기능까지) 🛠️

이 워크플로우는 Django 프로젝트를 시작하는 단계부터 기본적인 로그인 기능과 CRUD(Create, Read, Update, Delete) 기능을 구현하는 단계를 상세하게 안내하며, 각 코드 블록에 주석을 추가하여 코드의 이해도를 높입니다.

 

1. 프로젝트 및 앱 생성 🚀

  • 프로젝트 생성: Django 프로젝트는 웹 애플리케이션의 전체 설정을 담고 있는 컨테이너입니다.
    django-admin startproject myproject
    cd myproject
  • 앱 생성: 앱은 프로젝트 내에서 특정 기능을 담당하는 모듈입니다. 예를 들어, 블로그 앱, 사용자 관리 앱 등이 있습니다.
    python manage.py startapp blog
    python manage.py startapp accounts
  • settings.py 설정: myproject/settings.py 파일에 생성한 앱을 INSTALLED_APPS 목록에 추가합니다.
    # myproject/settings.py
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'blog',         # blog 앱 추가
        'accounts',     # accounts 앱 추가
    ]

 

2. 사용자 모델 및 인증 설정 🔒

  • 사용자 모델 정의 (accounts 앱): Django의 기본 사용자 모델(auth.User)을 사용하거나, 커스텀 사용자 모델을 정의할 수 있습니다. 커스텀 사용자 모델을 정의하려면 accounts/models.py 파일에 AbstractUser 또는 AbstractBaseUser를 상속받은 모델을 정의해야 합니다.
# accounts/models.py 
from django.contrib.auth.models import AbstractUser 
class User(AbstractUser): pass # 기본 사용자 모델을 확장하지 않고 그대로 사용

 

 

  • 커스텀 사용자 모델 설정: myproject/settings.py 파일에 커스텀 사용자 모델을 사용하도록 설정합니다.
# myproject/settings.py 
AUTH_USER_MODEL = 'accounts.User' # 커스텀 사용자 모델 사용 설정

 

 

  • 마이그레이션: 데이터베이스에 사용자 모델을 반영하기 위해 마이그레이션을 수행합니다
python manage.py makemigrations accounts # 마이그레이션 파일 생성 
python manage.py migrate accounts # 데이터베이스에 마이그레이션 적용

 

 

 

  • 로그인, 로그아웃 템플릿 생성: accounts 앱의 templates 디렉토리에 로그인 및 로그아웃 템플릿(login.html, logout.html)을 생성합니다.
  • 로그인, 로그아웃 기능 구현: accounts 앱의 views.py 파일에 로그인 및 로그아웃 기능을 구현합니다.
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import AuthenticationForm

def login_view(request):
    # POST 요청 시 로그인 처리
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST) # 로그인 폼 생성
        if form.is_valid(): # 폼 유효성 검사
            username = form.cleaned_data.get('username') # 폼 데이터에서 사용자 이름 가져오기
            password = form.cleaned_data.get('password') # 폼 데이터에서 비밀번호 가져오기
            user = authenticate(username=username, password=password) # 사용자 인증
            if user is not None: # 사용자 인증 성공 시
                login(request, user) # 사용자 로그인 처리
                return redirect('blog:post_list') # 블로그 메인 페이지로 이동
            else:
                return render(request, 'accounts/login.html', {'form': form, 'error': '로그인 실패'}) # 로그인 실패 시 오류 메시지 전달
    # GET 요청 시 로그인 폼 보여주기
    else:
        form = AuthenticationForm() # 빈 로그인 폼 생성
    return render(request, 'accounts/login.html', {'form': form}) # 로그인 폼 렌더링

def logout_view(request):
    logout(request) # 사용자 로그아웃 처리
    return redirect('accounts:login') # 로그아웃 후 로그인 페이지로 이동
  • URL 설정 (accounts 앱): accounts/urls.py 파일을 생성하고 로그인 및 로그아웃 URL을 설정합니다. myproject/urls.py 파일에 해당 URL을 포함합니다.
    # myproject/urls.py
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls), # 관리자 페이지 URL 설정
        path('accounts/', include('accounts.urls')), # accounts 앱 URL 포함
        path('blog/', include('blog.urls')), # blog 앱 URL 추가
    ]
  • # accounts/urls.py from django.urls import path from . import views app_name = 'accounts' urlpatterns = [ path('login/', views.login_view, name='login'), # 로그인 URL 패턴 설정 path('logout/', views.logout_view, name='logout'), # 로그아웃 URL 패턴 설정 ]
  • 템플릿 설정: 템플릿에서 로그인, 로그아웃 폼과 버튼을 생성하고, 로그인 상태에 따라 메뉴 등을 다르게 보여줄 수 있도록 설정합니다.

 

3. 모델 정의 (blog 앱) 📝

  • 모델 설계: 블로그 게시글을 저장할 모델(Post)을 blog/models.py 파일에 정의합니다. ForeignKey를 사용하여 사용자 모델과 연결할 수 있습니다.
from django.conf import settings
from django.db import models

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) # 작성자 ForeignKey 설정
    title = models.CharField(max_length=200) # 게시글 제목 필드
    content = models.TextField() # 게시글 내용 필드
    created_at = models.DateTimeField(auto_now_add=True) # 게시글 생성 시간 필드 (자동 설정)
    updated_at = models.DateTimeField(auto_now=True) # 게시글 수정 시간 필드 (자동 설정)

    def __str__(self):
        return self.title # 게시글 제목으로 객체 표현

 

 

  • 마이그레이션: 데이터베이스에 모델을 반영하기 위해 마이그레이션을 수행합니다.
# blog 앱에 대한 마이그레이션 파일 생성 
python manage.py makemigrations blog

# 데이터베이스에 blog 앱 마이그레이션 적용
python manage.py migrate blog

 

 

 

4. CRUD 기능 구현 (blog 앱) ⚙️

  • 폼 생성 (blog 앱): blog/forms.py 파일에 게시글 생성 및 수정을 위한 폼을 생성합니다.
from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    # 모델 폼 상속
    class Meta:
        model = Post  # 사용할 모델 지정
        fields = ['title', 'content']  # 폼에 포함할 필드 지정

 

 

  • 뷰 구현 (blog 앱): blog/views.py 파일에 게시글 목록, 상세 보기, 생성, 수정, 삭제 기능을 구현합니다.
    • @login_required 데코레이터: 로그인한 사용자만 해당 기능에 접근할 수 있도록 합니다.
from django.shortcuts import render, redirect, get_object_or_404
from .models import Post
from .forms import PostForm
from django.contrib.auth.decorators import login_required # 로그인 데코레이터 임포트

def post_list(request):
    posts = Post.objects.all() # 모든 게시글 가져오기
    return render(request, 'blog/post_list.html', {'posts': posts}) # 게시글 목록 템플릿 렌더링

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk) # 특정 pk의 게시글 가져오기 (없으면 404 에러)
    return render(request, 'blog/post_detail.html', {'post': post}) # 게시글 상세 템플릿 렌더링

@login_required # 로그인한 사용자만 접근 가능
def post_create(request):
    # POST 요청 시 게시글 생성
    if request.method == 'POST':
        form = PostForm(request.POST) # 폼 데이터로 PostForm 생성
        if form.is_valid(): # 폼 유효성 검사
            post = form.save(commit=False) # 게시글 저장 (커밋은 보류)
            post.author = request.user # 게시글 작성자 설정 (현재 로그인 사용자)
            post.save() # 게시글 저장 완료
            return redirect('blog:post_detail', pk=post.pk) # 게시글 상세 페이지로 리디렉션
    # GET 요청 시 폼 보여주기
    else:
        form = PostForm() # 빈 폼 생성
    return render(request, 'blog/post_form.html', {'form': form}) # 게시글 생성 폼 렌더링

@login_required # 로그인한 사용자만 접근 가능
def post_update(request, pk):
    post = get_object_or_404(Post, pk=pk) # 수정할 게시글 가져오기 (없으면 404 에러)
    # POST 요청 시 게시글 수정
    if request.method == 'POST':
        form = PostForm(request.POST, instance=post) # 폼 데이터로 PostForm 생성 (instance에 기존 게시글 설정)
        if form.is_valid(): # 폼 유효성 검사
            form.save() # 게시글 저장
            return redirect('blog:post_detail', pk=post.pk) # 게시글 상세 페이지로 리디렉션
    # GET 요청 시 폼 보여주기
    else:
        form = PostForm(instance=post) # 기존 게시글로 채워진 폼 생성
    return render(request, 'blog/post_form.html', {'form': form}) # 게시글 수정 폼 렌더링

@login_required # 로그인한 사용자만 접근 가능
def post_delete(request, pk):
    post = get_object_or_404(Post, pk=pk) # 삭제할 게시글 가져오기 (없으면 404 에러)
    post.delete() # 게시글 삭제
    return redirect('blog:post_list') # 게시글 목록 페이지로 리디렉션

 

 

 

  • URL 설정 (blog 앱): blog/urls.py 파일을 생성하고, 각 뷰 함수에 해당하는 URL 패턴을 정의합니다. myproject/urls.py 파일에 해당 URL을 포함합니다.
    # myproject/urls.py
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls), # 관리자 페이지 URL 설정
        path('accounts/', include('accounts.urls')), # accounts 앱 URL 포함
        path('blog/', include('blog.urls')), # blog 앱 URL 포함
    ]
from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
    path('', views.post_list, name='post_list'),  # 게시글 목록 URL 패턴 설정
    path('<int:pk>/', views.post_detail, name='post_detail'),  # 게시글 상세 URL 패턴 설정
    path('create/', views.post_create, name='post_create'),  # 게시글 생성 URL 패턴 설정
    path('<int:pk>/update/', views.post_update, name='post_update'),  # 게시글 수정 URL 패턴 설정
    path('<int:pk>/delete/', views.post_delete, name='post_delete'),  # 게시글 삭제 URL 패턴 설정
]

    

 

 

 

5. 템플릿 생성 (blog 앱) 🖼️ 

  • 템플릿 파일 생성: blog/templates/blog 디렉토리에 post_list.html, post_detail.html, post_form.html 템플릿 파일을 생성합니다.
  • 템플릿 구성 (예시):
    • post_list.html (게시글 목록 템플릿):
      • 설명:
        • {% for post in posts %}: 템플릿 변수 posts에 담긴 게시글 객체들을 반복하여 출력합니다.
        • {{ post.title }}: 게시글 제목을 출력합니다.
        • {{ post.author.username }}: 게시글 작성자의 사용자 이름을 출력합니다.
        • {% url 'blog:post_detail' pk=post.pk %}: blog 앱의 post_detail URL 패턴에 게시글의 pk 값을 전달하여 상세 페이지 링크를 생성합니다.
        • {% url 'blog:post_create' %}: blog 앱의 post_create URL 패턴으로 이동하는 링크를 생성합니다.
        • {% url 'blog:post_update' pk=post.pk %}: blog 앱의 post_update URL 패턴에 게시글의 pk 값을 전달하여 수정 페이지 링크를 생성합니다.
        • {% url 'blog:post_delete' pk=post.pk %}: blog 앱의 post_delete URL 패턴에 게시글의 pk 값을 전달하여 삭제 페이지 링크를 생성합니다.
<!DOCTYPE html>
<html>
<head>
    <title>게시글 목록</title>
</head>
<body>
    <h1>게시글 목록</h1>
    <ul>
        {% for post in posts %}
        <li>
            <a href="{% url 'blog:post_detail' pk=post.pk %}">{{ post.title }}</a> (작성자: {{ post.author.username }})
            <a href="{% url 'blog:post_update' pk=post.pk %}">수정</a>
            <a href="{% url 'blog:post_delete' pk=post.pk %}">삭제</a>
        </li>
        {% endfor %}
    </ul>
    <a href="{% url 'blog:post_create' %}">새 게시글 작성</a>
</body>
</html>

 

    • post_detail.html (게시글 상세 템플릿):
      • 설명:
        • {{ post.title }}: 게시글 제목을 출력합니다.
        • {{ post.content }}: 게시글 내용을 출력합니다.
        • {{ post.author.username }}: 게시글 작성자의 사용자 이름을 출력합니다.
        • {{ post.created_at }}: 게시글 생성 시간을 출력합니다.
        • {{ post.updated_at }}: 게시글 수정 시간을 출력합니다.
        • {% url 'blog:post_update' pk=post.pk %}: blog 앱의 post_update URL 패턴에 게시글의 pk 값을 전달하여 수정 페이지 링크를 생성합니다.
        • {% url 'blog:post_delete' pk=post.pk %}: blog 앱의 post_delete URL 패턴에 게시글의 pk 값을 전달하여 삭제 페이지 링크를 생성합니다.
        • {% url 'blog:post_list' %}: blog 앱의 post_list URL 패턴으로 이동하는 목록 페이지 링크를 생성합니다.
<!DOCTYPE html>
<html>
<head>
    <title>{{ post.title }}</title>
</head>
<body>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
    <p>작성자: {{ post.author.username }}</p>
    <p>작성일: {{ post.created_at }}</p>
    <p>수정일: {{ post.updated_at }}</p>
    <a href="{% url 'blog:post_update' pk=post.pk %}">수정</a>
    <a href="{% url 'blog:post_delete' pk=post.pk %}">삭제</a>
    <a href="{% url 'blog:post_list' %}">목록으로</a>
</body>
</html>

 

 

  • post_form.html (게시글 생성/수정 폼 템플릿):
    • 설명:
      • {% csrf_token %}: CSRF 공격 방지 토큰을 포함합니다.
      • {{ form.as_p }}: 폼 필드를 p 태그로 감싸서 출력합니다. (다른 렌더링 옵션도 사용 가능)
      • <button type="submit">저장</button>: 폼 제출 버튼입니다.
      • {% url 'blog:post_list' %}: blog 앱의 post_list URL 패턴으로 이동하는 목록 페이지 링크를 생성합니다.
```html
  <!DOCTYPE html>
  <html>
  <head>
      <title>로그인</title>
  </head>
  <body>
      <h1>로그인</h1>
      <form method="post">
          {% csrf_token %}
          {{ form.as_p }}
          {% if error %}
            <p style="color:red">{{ error }}</p>
          {% endif %}
          <button type="submit">로그인</button>
      </form>
  </body>
  </html>
```
*   **설명:**
  *   `{% csrf_token %}`: CSRF 공격 방지 토큰을 포함합니다.
  *   `{{ form.as_p }}`: 로그인 폼 필드를 `p` 태그로 감싸서 출력합니다.
    *   `{% if error %}`:  로그인 실패 시 에러 메세지를 출력합니다.
  *    `<button type="submit">로그인</button>`: 폼 제출 버튼입니다.
  • *로그인 템플릿 (accounts 앱): `accounts/templates/accounts` 디렉토리에 `login.html` 템플릿 파일을 생성합니다.
  • 로그아웃 템플릿 (accounts 앱): accounts/templates/accounts 디렉토리에 logout.html 템플릿 파일을 생성합니다.
    • 설명:
      • 로그아웃 완료 메세지를 출력하고 로그인 페이지로 이동하는 링크를 제공합니다.
<!DOCTYPE html>
<html>
<head>
    <title>로그아웃</title>
</head>
<body>
    <h1>로그아웃 되었습니다.</h1>
    <a href="{% url 'accounts:login' %}">다시 로그인하기</a>
</body>
</html>

 

6. 테스트 및 디버깅 🧪

  • Django 개발 서버 실행:
    python manage.py runserver
  • 기능 테스트: 웹 브라우저를 통해 로그인, 로그아웃, 게시글 목록, 상세 보기, 생성, 수정, 삭제 기능을 테스트합니다.
  • 디버깅: 코드에 오류가 있으면, 오류 메시지를 확인하고 코드를 수정합니다.

 

7. 추가 기능 구현 (선택 사항) ✨

  • 페이지네이션: 게시글 목록 페이지에 페이지네이션을 추가하여 게시글이 많을 때 효율적으로 관리할 수 있도록 합니다.
  • 검색 기능: 게시글 제목이나 내용으로 게시글을 검색할 수 있도록 합니다.
  • 권한 관리: 특정 사용자에게만 게시글을 생성, 수정, 삭제 권한을 부여합니다.
  • CSS 적용: 웹 페이지에 스타일을 적용하여 디자인을 개선합니다.

 

'Python > Django' 카테고리의 다른 글

관계형 데이터베이스 보충  (3) 2025.01.09
Django AUTH USER 사용자 모델  (2) 2025.01.08
다대다 관계 보충설명  (7) 2025.01.08
[TIL] ForeignKey 보충 (코드예시)  (0) 2025.01.08
[TIL] Django Model, foreignkey와 migration  (0) 2025.01.07