Django로 웹 애플리케이션 만들기: 초보자도 쉽게 따라할 수 있는 단계별 튜토리얼 가이드 🚀

🐍 Python + Django = 웹 개발의 완벽한 조합! 🌐
안녕하세요 여러분! 오늘은 2025년 3월 17일, 파이썬 웹 프레임워크의 절대강자 Django(장고)로 웹 애플리케이션을 만드는 방법을 처음부터 끝까지 함께 알아볼게요! 코딩 초보자도 따라할 수 있게 최대한 쉽게 설명해드릴게요. 진짜 쉽게요, 진짜로! ㅋㅋㅋ
📑 목차
- Django란 무엇인가요?
- 개발 환경 설정하기
- 첫 번째 Django 프로젝트 만들기
- Django 앱 생성하기
- 모델 설계하기
- 관리자 페이지 사용하기
- URL 설정하기
- View 작성하기
- Template 만들기
- 정적 파일 관리하기
- 폼 처리하기
- 사용자 인증 구현하기
- 배포 준비하기
- 마무리 및 다음 단계
1. Django란 무엇인가요? 🤔
Django(장고)는 Python으로 작성된 오픈 소스 웹 프레임워크예요. 2005년에 처음 출시된 이후로 계속 발전해왔고, 2025년 현재 Django 5.1 버전까지 나왔어요! 인스타그램, 핀터레스트, 모질라 같은 대형 서비스들도 Django로 만들어졌다는 거 알고 계셨나요? 대박이죠? 😲
Django의 철학은 "Don't Repeat Yourself" (DRY)와 "Batteries Included"예요. 코드 재사용을 장려하고, 웹 개발에 필요한 대부분의 기능이 이미 내장되어 있어요. 그래서 개발자들이 비즈니스 로직에 집중할 수 있게 해준답니다!
Django는 MTV(Model-Template-View) 패턴을 사용해요. 이건 MVC(Model-View-Controller) 패턴과 비슷한데, 이름만 좀 다르게 부르는 거예요.
- 🔹 Model: 데이터베이스와 상호작용하는 부분
- 🔹 Template: 사용자에게 보여지는 HTML 부분
- 🔹 View: 비즈니스 로직을 처리하는 부분
이제 Django가 뭔지 대충 감이 오시죠? 그럼 바로 실전으로 들어가볼게요! 🏃♂️
2. 개발 환경 설정하기 ⚙️
Django로 개발하기 전에 필요한 것들을 설치해볼게요. 진짜 별거 없어요! 파이썬이랑 Django만 있으면 됩니다!
2.1 Python 설치하기
Django는 Python으로 만들어졌기 때문에 당연히 Python이 필요해요. 2025년 3월 기준으로 Python 3.12 이상을 추천해요.
Python 설치는 Python 공식 웹사이트에서 할 수 있어요. 설치할 때 'Add Python to PATH' 옵션을 꼭 체크해주세요! 안 그러면 나중에 머리 아파요... ㅋㅋㅋ
2.2 가상환경 만들기
가상환경이 뭐냐고요? 쉽게 말하면 프로젝트마다 별도의 "방"을 만들어서 각 프로젝트에 필요한 라이브러리들이 서로 충돌하지 않게 해주는 거예요. 진짜 필수입니다! 안 그러면 나중에 프로젝트 여러 개 하다가 대환장 파티 열려요... 😱
터미널(맥/리눅스) 또는 명령 프롬프트(윈도우)를 열고 다음 명령어를 입력해볼게요:
# 가상환경 생성하기
python -m venv django_env
# 가상환경 활성화하기 (윈도우)
django_env\Scripts\activate
# 가상환경 활성화하기 (맥/리눅스)
source django_env/bin/activate
가상환경이 활성화되면 터미널 앞에 (django_env)
같은 표시가 나타나요. 이제 이 "방" 안에서 Django를 설치할 준비가 됐어요!
2.3 Django 설치하기
이제 진짜 Django를 설치해볼게요. pip라는 파이썬 패키지 관리자를 사용할 거예요:
# Django 최신 버전 설치하기
pip install django
2025년 3월 기준으로 Django 5.1 버전이 설치될 거예요. 설치가 완료되면 다음 명령어로 제대로 설치됐는지 확인해볼까요?
python -m django --version
버전 번호가 나오면 성공이에요! 🎉 이제 Django 프로젝트를 시작할 준비가 됐어요!
💡 꿀팁!
개발할 때 도움이 되는 추가 도구들도 설치해보세요:
- VS Code: 무료 코드 에디터로 Django 개발에 딱이에요!
- Django Extensions:
pip install django-extensions
로 설치하면 개발할 때 유용한 기능들을 추가해줘요. - Django Debug Toolbar:
pip install django-debug-toolbar
로 설치하면 디버깅이 훨씬 쉬워져요.
3. 첫 번째 Django 프로젝트 만들기 🎬
자, 이제 진짜 Django 프로젝트를 만들어볼게요! 너무 설레지 않나요? ㅋㅋㅋ
3.1 프로젝트 생성하기
Django에는 프로젝트를 쉽게 시작할 수 있는 명령어가 있어요. 터미널에서 다음 명령어를 입력해보세요:
django-admin startproject mywebsite
이 명령어는 mywebsite
라는 이름의 Django 프로젝트를 생성해요. 물론 여러분이 원하는 이름으로 바꿔도 돼요! 'coolproject', 'awesome_blog' 뭐 이런 식으로요. 근데 공백이나 특수문자는 쓰지 마세요! 파이썬이 싫어해요... 😅
3.2 프로젝트 구조 살펴보기
프로젝트가 생성되면 다음과 같은 구조가 만들어져요:
mywebsite/
├── manage.py
└── mywebsite/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
각 파일의 역할을 간단히 설명해드릴게요:
- 🔸 manage.py: Django 프로젝트를 관리하는 명령행 유틸리티
- 🔸 __init__.py: 이 디렉토리가 파이썬 패키지임을 알려주는 빈 파일
- 🔸 settings.py: 프로젝트의 설정을 담고 있는 파일 (진짜 중요!)
- 🔸 urls.py: URL 패턴을 정의하는 파일
- 🔸 asgi.py: ASGI 호환 웹 서버를 위한 진입점
- 🔸 wsgi.py: WSGI 호환 웹 서버를 위한 진입점
처음에는 이게 다 뭔지 몰라도 괜찮아요! 저도 처음에는 몰랐어요... ㅋㅋㅋ 하나씩 알아가면 돼요!
3.3 개발 서버 실행하기
이제 Django의 개발 서버를 실행해볼게요. 이 서버는 개발 중에만 사용하는 간단한 웹 서버예요. 프로젝트 폴더로 이동해서 다음 명령어를 실행해보세요:
cd mywebsite
python manage.py runserver
터미널에 다음과 비슷한 메시지가 나타날 거예요:
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
March 17, 2025 - 15:50:53
Django version 5.1, using settings 'mywebsite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
이제 웹 브라우저를 열고 http://127.0.0.1:8000으로 접속해보세요. 짜잔! 🎉 Django의 환영 페이지가 보일 거예요!
축하합니다! 🎊 여러분의 첫 번째 Django 프로젝트가 실행됐어요! 아직은 빈 프로젝트지만, 이제부터 하나씩 채워나갈 거예요!
⚠️ 주의사항
터미널에 나온 마이그레이션 경고는 무시하지 마세요! 다음 단계에서 해결할 거예요. 마이그레이션은 데이터베이스 구조를 변경하는 Django의 방식이에요.
4. Django 앱 생성하기 📱
Django에서는 프로젝트를 여러 개의 "앱(App)"으로 나눠서 관리해요. 앱은 특정 기능을 담당하는 모듈이라고 생각하면 돼요. 예를 들어, 블로그 프로젝트라면 'posts', 'comments', 'users' 같은 앱들로 나눌 수 있어요.
4.1 앱 생성하기
우리는 간단한 블로그 앱을 만들어볼게요. 터미널에서 다음 명령어를 실행해보세요:
python manage.py startapp blog
이 명령어는 blog
라는 이름의 앱을 생성해요. 이제 프로젝트 구조가 다음과 같이 변경됐을 거예요:
mywebsite/
├── blog/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations/
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
└── mywebsite/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
각 파일의 역할을 간단히 설명해드릴게요:
- 🔹 admin.py: 관리자 페이지 설정
- 🔹 apps.py: 앱 설정
- 🔹 migrations/: 데이터베이스 변경사항 관리
- 🔹 models.py: 데이터 모델 정의
- 🔹 tests.py: 테스트 코드 작성
- 🔹 views.py: 뷰 함수 정의
4.2 앱 등록하기
앱을 만들었으면 Django에게 이 앱을 사용할 거라고 알려줘야 해요. mywebsite/settings.py
파일을 열고 INSTALLED_APPS
리스트에 우리가 만든 앱을 추가해주세요:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # 우리가 만든 앱 추가
]
4.3 데이터베이스 마이그레이션 실행하기
앞서 개발 서버를 실행했을 때 마이그레이션 관련 경고가 나왔죠? 이제 그 문제를 해결해볼게요. 마이그레이션은 Django가 데이터베이스 스키마를 관리하는 방법이에요.
python manage.py migrate
이 명령어를 실행하면 Django가 기본 앱들에 필요한 데이터베이스 테이블을 생성해요. 터미널에 여러 줄의 "OK"가 표시되면 성공한 거예요!
💡 꿀팁!
Django는 기본적으로 SQLite 데이터베이스를 사용해요. 이건 파일 기반 데이터베이스라서 별도의 설치 없이 바로 사용할 수 있어요. 실제 서비스에서는 PostgreSQL이나 MySQL 같은 더 강력한 데이터베이스를 사용하는 게 좋아요!
5. 모델 설계하기 📊
이제 블로그 앱의 데이터 모델을 설계해볼게요. 모델은 데이터베이스의 구조를 정의하는 부분이에요. 블로그니까 당연히 "게시물(Post)" 모델이 필요하겠죠?
5.1 모델 정의하기
blog/models.py
파일을 열고 다음과 같이 수정해주세요:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
이 코드는 Post
라는 모델을 정의해요. 각 필드의 의미는 다음과 같아요:
- 🔸 title: 게시물 제목 (최대 200자)
- 🔸 content: 게시물 내용 (텍스트)
- 🔸 created_date: 게시물 생성 날짜 (자동으로 현재 시간 설정)
- 🔸 published_date: 게시물 발행 날짜 (선택적)
- 🔸 author: 게시물 작성자 (User 모델과 연결)
또한 두 개의 메서드도 정의했어요:
- 🔸 publish(): 게시물을 발행하는 메서드
- 🔸 __str__(): 객체를 문자열로 표현할 때 사용하는 메서드
5.2 모델 마이그레이션 생성하기
모델을 정의했으니 이제 이 모델에 맞는 데이터베이스 테이블을 생성해야 해요. Django의 마이그레이션 시스템을 사용해서 모델 변경사항을 데이터베이스에 적용할 수 있어요.
python manage.py makemigrations blog
이 명령어는 blog
앱의 모델 변경사항을 감지하고 마이그레이션 파일을 생성해요. 터미널에 다음과 비슷한 메시지가 나타날 거예요:
Migrations for 'blog':
blog/migrations/0001_initial.py
- Create model Post
5.3 마이그레이션 적용하기
이제 생성된 마이그레이션을 데이터베이스에 적용해볼게요:
python manage.py migrate blog
이 명령어는 blog
앱의 마이그레이션을 데이터베이스에 적용해요. 터미널에 "OK"가 표시되면 성공한 거예요!
축하합니다! 이제 데이터베이스에 블로그 게시물을 저장할 수 있는 테이블이 생성됐어요! 다음 단계에서는 이 모델을 관리자 페이지에 등록해서 쉽게 관리할 수 있게 만들어볼게요.
6. 관리자 페이지 사용하기 👨💼
Django의 가장 강력한 기능 중 하나는 자동으로 생성되는 관리자 페이지예요. 이 페이지를 통해 모델 데이터를 쉽게 관리할 수 있어요. 진짜 개발자들이 엄청 좋아하는 기능이에요! ㅋㅋㅋ
6.1 관리자 계정 생성하기
관리자 페이지에 접속하려면 먼저 관리자 계정을 생성해야 해요. 다음 명령어를 실행해보세요:
python manage.py createsuperuser
이 명령어를 실행하면 사용자 이름, 이메일 주소, 비밀번호를 입력하라는 메시지가 나타나요. 원하는 정보를 입력하고 계정을 생성해주세요. 비밀번호는 보안을 위해 화면에 표시되지 않아요!
6.2 모델을 관리자 페이지에 등록하기
이제 Post
모델을 관리자 페이지에 등록해볼게요. blog/admin.py
파일을 열고 다음과 같이 수정해주세요:
from django.contrib import admin
from .models import Post
admin.site.register(Post)
이 코드는 Post
모델을 관리자 페이지에 등록해요. 이제 관리자 페이지에서 게시물을 생성, 수정, 삭제할 수 있어요!
6.3 관리자 페이지 접속하기
개발 서버를 실행하고 관리자 페이지에 접속해볼게요:
python manage.py runserver
웹 브라우저에서 http://127.0.0.1:8000/admin/으로 접속하면 로그인 페이지가 나타나요. 앞서 생성한 관리자 계정으로 로그인해보세요.
로그인하면 관리자 대시보드가 나타나요. 여기서 "Posts" 링크를 클릭하면 게시물 목록 페이지로 이동해요. "Add Post" 버튼을 클릭해서 새 게시물을 생성해보세요!
6.4 관리자 페이지 커스터마이징
기본 관리자 페이지도 좋지만, 더 사용하기 편하게 커스터마이징할 수도 있어요. blog/admin.py
파일을 다음과 같이 수정해보세요:
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'created_date', 'published_date')
list_filter = ('created_date', 'published_date', 'author')
search_fields = ('title', 'content')
date_hierarchy = 'created_date'
ordering = ('-created_date',)
이 코드는 Post
모델의 관리자 페이지를 다음과 같이 커스터마이징해요:
- 🔹 list_display: 목록 페이지에 표시할 필드
- 🔹 list_filter: 필터링 옵션
- 🔹 search_fields: 검색 가능한 필드
- 🔹 date_hierarchy: 날짜 기반 탐색
- 🔹 ordering: 정렬 방식 (- 기호는 내림차순)
개발 서버를 다시 실행하고 관리자 페이지에 접속해보세요. 훨씬 더 사용하기 편해졌죠? 😎
💡 꿀팁!
관리자 페이지는 개발 중에 데이터를 관리하기 좋은 도구지만, 실제 사용자들이 사용할 인터페이스는 아니에요. 다음 단계에서는 사용자들이 볼 수 있는 페이지를 만들어볼게요!
7. URL 설정하기 🔗
이제 사용자들이 웹사이트에 접속했을 때 볼 수 있는 페이지를 만들어볼게요. Django에서는 URL 패턴을 정의해서 특정 URL에 접속했을 때 어떤 뷰 함수를 실행할지 결정해요.
7.1 앱 URL 설정 파일 생성하기
먼저 blog
앱에 URL 설정 파일을 생성해볼게요. blog
디렉토리 안에 urls.py
파일을 생성하고 다음 코드를 작성해주세요:
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<pk>/edit/', views.post_edit, name='post_edit'),
]</pk></pk>
이 코드는 다음과 같은 URL 패턴을 정의해요:
- 🔸 /: 게시물 목록 페이지
- 🔸 /post/1/: ID가 1인 게시물의 상세 페이지
- 🔸 /post/new/: 새 게시물 작성 페이지
- 🔸 /post/1/edit/: ID가 1인 게시물의 수정 페이지
각 URL 패턴은 해당하는 뷰 함수와 연결되어 있어요. 아직 이 뷰 함수들을 작성하지 않았지만, 곧 작성할 거예요!
7.2 프로젝트 URL 설정에 앱 URL 포함시키기
이제 프로젝트의 메인 URL 설정 파일에 앱의 URL 설정을 포함시켜야 해요. mywebsite/urls.py
파일을 열고 다음과 같이 수정해주세요:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
이 코드는 루트 URL('/')에 접속했을 때 blog.urls
에 정의된 URL 패턴을 사용하도록 설정해요. 이제 사용자가 웹사이트에 접속하면 블로그 앱의 페이지가 표시될 거예요!
URL 패턴을 정의했으니 이제 뷰 함수를 작성해볼게요!
8. View 작성하기 👁️
뷰(View)는 웹 요청을 받아서 처리하고 응답을 반환하는 함수예요. Django에서는 뷰 함수가 모델에서 데이터를 가져와서 템플릿에 전달하는 역할을 해요.
8.1 게시물 목록 뷰 작성하기
blog/views.py
파일을 열고 다음 코드를 작성해주세요:
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Post
from .forms import PostForm
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
이 코드는 post_list
뷰 함수를 정의해요. 이 함수는 다음과 같은 작업을 수행해요:
- 발행된 게시물을 발행일 기준으로 내림차순 정렬해서 가져와요.
blog/post_list.html
템플릿을 렌더링해요.- 템플릿에
posts
변수를 전달해요.
8.2 게시물 상세 뷰 작성하기
이어서 post_detail
뷰 함수를 작성해볼게요:
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
이 함수는 특정 ID(pk)를 가진 게시물을 가져와서 blog/post_detail.html
템플릿에 전달해요. get_object_or_404
함수는 해당 객체가 없을 경우 404 에러를 발생시켜요.
8.3 폼 클래스 작성하기
게시물을 생성하고 수정하는 뷰를 작성하기 전에 먼저 폼 클래스를 정의해야 해요. blog
디렉토리 안에 forms.py
파일을 생성하고 다음 코드를 작성해주세요:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'content',)
이 코드는 Post
모델을 기반으로 한 PostForm
클래스를 정의해요. 이 폼은 title
과 content
필드만 포함해요.
8.4 게시물 생성 뷰 작성하기
이제 views.py
파일에 post_new
함수를 추가해볼게요:
def post_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('blog:post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
이 함수는 다음과 같은 작업을 수행해요:
- GET 요청일 경우 빈 폼을 표시해요.
- POST 요청일 경우 폼 데이터를 검증해요.
- 폼이 유효하면 게시물을 저장하고 상세 페이지로 리다이렉트해요.
- 폼이 유효하지 않으면 오류 메시지와 함께 폼을 다시 표시해요.
8.5 게시물 수정 뷰 작성하기
마지막으로 post_edit
함수를 추가해볼게요:
def post_edit(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('blog:post_detail', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'blog/post_edit.html', {'form': form})
이 함수는 post_new
함수와 비슷하지만, 기존 게시물을 수정한다는 점이 달라요. instance=post
매개변수를 사용해서 폼을 초기화해요.
⚠️ 주의사항
위 코드에서는 간단하게 구현하기 위해 로그인한 사용자만 게시물을 작성하고 수정할 수 있도록 하는 권한 검사를 생략했어요. 실제 프로젝트에서는 @login_required
데코레이터나 권한 검사 코드를 추가하는 것이 좋아요!
이제 뷰 함수를 모두 작성했어요! 하지만 아직 템플릿이 없어서 실행하면 오류가 발생할 거예요. 다음 단계에서 템플릿을 만들어볼게요!
9. Template 만들기 🎨
템플릿은 사용자에게 보여지는 HTML 페이지를 정의해요. Django의 템플릿 언어를 사용하면 동적인 웹 페이지를 쉽게 만들 수 있어요.
9.1 템플릿 디렉토리 구조 만들기
먼저 템플릿 파일을 저장할 디렉토리 구조를 만들어볼게요:
blog/
└── templates/
└── blog/
├── base.html
├── post_list.html
├── post_detail.html
└── post_edit.html
blog
디렉토리 안에 templates
디렉토리를 만들고, 그 안에 다시 blog
디렉토리를 만들어주세요. 이렇게 중첩된 구조를 사용하는 이유는 템플릿 이름 충돌을 방지하기 위해서예요.
9.2 기본 템플릿 만들기
먼저 모든 페이지의 기본 구조를 정의하는 base.html
파일을 만들어볼게요:
<!DOCTYPE html>
<html>
<head>
<title>Django Blog</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body>
<header class="py-3 mb-4 border-bottom">
<div class="container d-flex flex-wrap justify-content-center">
<a href="{% url 'blog:post_list' %}" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
<span class="fs-4">Django Blog</span>
</a>
<ul class="nav nav-pills">
<li class="nav-item"><a href="{% url 'blog:post_list' %}" class="nav-link">Home</a></li>
<li class="nav-item"><a href="{% url 'blog:post_new' %}" class="nav-link">New Post</a></li>
</ul>
</div>
</header>
<main class="container">
{% block content %}
{% endblock %}
</main>
<footer class="py-3 my-4">
<div class="container text-center">
<p class="text-muted">Django Blog - Created with ❤️ using Django</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
이 템플릿은 Bootstrap 5를 사용해서 기본적인 레이아웃을 정의해요. {% block content %}
와 {% endblock %}
사이에 각 페이지의 고유한 내용이 들어갈 거예요.
9.3 게시물 목록 템플릿 만들기
이제 post_list.html
파일을 만들어볼게요:
{% extends 'blog/base.html' %}
{% block content %}
<h1 class="my-4">Latest Posts</h1>
{% for post in posts %}
<article class="card mb-4">
<div class="card-body">
<h2 class="card-title">
<a href="{% url 'blog:post_detail' pk=post.pk %}">{{ post.title }}</a>
</h2>
<p class="card-text text-muted">
Published on {{ post.published_date }} by {{ post.author }}
</p>
<p class="card-text">{{ post.content|truncatewords:30 }}</p>
<a href="{% url 'blog:post_detail' pk=post.pk %}" class="btn btn-primary">Read more</a>
</div>
</article>
{% empty %}
<div class="alert alert-info">No posts yet. Why not create one?</div>
{% endfor %}
{% endblock %}
이 템플릿은 base.html
을 확장해서 게시물 목록을 표시해요. {% for post in posts %}
태그를 사용해서 뷰에서 전달받은 게시물 목록을 반복해서 표시해요. {% empty %}
태그는 게시물이 없을 경우 표시할 내용을 정의해요.
9.4 게시물 상세 템플릿 만들기
다음으로 post_detail.html
파일을 만들어볼게요:
{% extends 'blog/base.html' %}
{% block content %}
<article class="my-4">
<h1>{{ post.title }}</h1>
<p class="text-muted">
Published on {{ post.published_date }} by {{ post.author }}
</p>
<div class="my-4">
{{ post.content|linebreaks }}
</div>
<div class="mt-4">
<a href="{% url 'blog:post_edit' pk=post.pk %}" class="btn btn-secondary">Edit post</a>
<a href="{% url 'blog:post_list' %}" class="btn btn-outline-primary">Back to list</a>
</div>
</article>
{% endblock %}
이 템플릿은 게시물의 제목, 작성자, 발행일, 내용을 표시해요. {{ post.content|linebreaks }}
에서 linebreaks
필터는 텍스트의 줄바꿈을 HTML의 <p>
태그로 변환해줘요.
9.5 게시물 폼 템플릿 만들기
마지막으로 post_edit.html
파일을 만들어볼게요:
{% extends 'blog/base.html' %}
{% block content %}
<h1 class="my-4">{% if form.instance.pk %}Edit Post{% else %}New Post{% endif %}</h1>
<form method="post" class="card p-4">
{% csrf_token %}
<div class="mb-3">
<label for="id_title" class="form-label">Title</label>
{{ form.title.errors }}
<input type="text" name="title" id="id_title" class="form-control" value="{{ form.title.value|default:'' }}" required>
</div>
<div class="mb-3">
<label for="id_content" class="form-label">Content</label>
{{ form.content.errors }}
<textarea name="content" id="id_content" class="form-control" rows="10" required>{{ form.content.value|default:'' }}</textarea>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="submit" class="btn btn-primary">Save</button>
<a href="{% url 'blog:post_list' %}" class="btn btn-outline-secondary">Cancel</a>
</div>
</form>
{% endblock %}
이 템플릿은 게시물 생성과 수정에 모두 사용돼요. {% if form.instance.pk %}
조건문을 사용해서 폼이 기존 게시물을 수정하는지 새 게시물을 생성하는지 구분해요. {% csrf_token %}
태그는 CSRF(Cross-Site Request Forgery) 공격을 방지하기 위한 보안 토큰을 추가해요.
이제 템플릿을 모두 만들었어요! 개발 서버를 실행하고 http://127.0.0.1:8000에 접속해보세요. 블로그 앱이 잘 작동하는지 확인해보세요!
💡 꿀팁!
Django 템플릿 언어에는 다양한 태그와 필터가 있어요. Django 공식 문서에서 더 많은 정보를 확인할 수 있어요!
10. 정적 파일 관리하기 📁
웹사이트를 더 멋지게 만들려면 CSS, JavaScript, 이미지 같은 정적 파일이 필요해요. Django에서는 이런 정적 파일을 관리하는 방법을 제공해요.
10.1 정적 파일 디렉토리 구조 만들기
먼저 정적 파일을 저장할 디렉토리 구조를 만들어볼게요:
blog/
└── static/
└── blog/
├── css/
│ └── blog.css
├── js/
│ └── blog.js
└── images/
└── django-logo.png
blog
디렉토리 안에 static
디렉토리를 만들고, 그 안에 다시 blog
디렉토리를 만들어주세요. 템플릿과 마찬가지로 이렇게 중첩된 구조를 사용하는 이유는 정적 파일 이름 충돌을 방지하기 위해서예요.
10.2 CSS 파일 만들기
blog/static/blog/css/blog.css
파일을 만들고 다음 코드를 작성해주세요:
body {
font-family: 'Roboto', sans-serif;
line-height: 1.6;
color: #333;
background-color: #f9f9f9;
}
.blog-header {
background-color: #092e20;
color: white;
padding: 2rem 0;
margin-bottom: 2rem;
}
.blog-title {
font-weight: bold;
}
.card {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.card:hover {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.btn-primary {
background-color: #092e20;
border-color: #092e20;
}
.btn-primary:hover {
background-color: #0c4b33;
border-color: #0c4b33;
}
10.3 템플릿에 정적 파일 포함시키기
base.html
파일을 수정해서 CSS 파일을 포함시켜볼게요:
<!DOCTYPE html>
<html>
<head>
<title>Django Blog</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
{% load static %}
<link rel="stylesheet" href="{% static 'blog/css/blog.css' %}">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap">
</head>
<body>
<header class="blog-header py-3 mb-4 border-bottom">
<div class="container d-flex flex-wrap justify-content-center">
<a href="{% url 'blog:post_list' %}" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
<span class="fs-4 blog-title">Django Blog</span>
</a>
<ul class="nav nav-pills">
<li class="nav-item"><a href="{% url 'blog:post_list' %}" class="nav-link text-white">Home</a></li>
<li class="nav-item"><a href="{% url 'blog:post_new' %}" class="nav-link text-white">New Post</a></li>
</ul>
</div>
</header>
<main class="container">
{% block content %}
{% endblock %}
</main>
<footer class="py-3 my-4">
<div class="container text-center">
<p class="text-muted">Django Blog - Created with ❤️ using Django</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="{% static 'blog/js/blog.js' %}"></script>
</body>
</html>
{% load static %}
태그는 정적 파일 템플릿 태그를 로드해요. {% static 'blog/css/blog.css' %}
태그는 정적 파일의 URL을 생성해요.
10.4 JavaScript 파일 만들기
blog/static/blog/js/blog.js
파일을 만들고 다음 코드를 작성해주세요:
// 페이지가 로드되면 실행
document.addEventListener('DOMContentLoaded', function() {
console.log('Django Blog loaded!');
// 카드에 마우스 오버 효과 추가
const cards = document.querySelectorAll('.card');
cards.forEach(card => {
card.addEventListener('mouseenter', function() {
this.style.cursor = 'pointer';
});
// 카드 클릭 시 해당 게시물로 이동
card.addEventListener('click', function(e) {
// 이미 클릭된 요소가 링크나 버튼이면 기본 동작 유지
if (e.target.tagName === 'A' || e.target.tagName === 'BUTTON') {
return;
}
// 카드 내부의 첫 번째 링크 찾기
const link = this.querySelector('a');
if (link) {
window.location.href = link.href;
}
});
});
});
이 JavaScript 코드는 게시물 카드에 마우스 오버 효과를 추가하고, 카드를 클릭하면 해당 게시물의 상세 페이지로 이동하도록 해요.
💡 꿀팁!
개발 모드에서는 Django가 자동으로 정적 파일을 제공하지만, 프로덕션 환경에서는 collectstatic
명령어를 사용해서 정적 파일을 수집하고 웹 서버를 통해 제공해야 해요. 이에 대해서는 배포 단계에서 더 자세히 알아볼게요!
11. 폼 처리하기 📝
이미 기본적인 폼 처리 기능을 구현했지만, 이번에는 좀 더 복잡한 폼을 만들어볼게요. 게시물에 댓글을 추가하는 기능을 구현해볼게요!
11.1 댓글 모델 추가하기
blog/models.py
파일에 Comment
모델을 추가해주세요:
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved = models.BooleanField(default=False)
def approve(self):
self.approved = True
self.save()
def __str__(self):
return self.text
이 모델은 게시물에 대한 댓글을 나타내요. related_name='comments'
매개변수를 사용하면 post.comments.all()
과 같이 게시물의 모든 댓글에 접근할 수 있어요.
11.2 마이그레이션 생성 및 적용하기
새 모델을 추가했으니 마이그레이션을 생성하고 적용해볼게요:
python manage.py makemigrations blog
python manage.py migrate blog
11.3 댓글 폼 추가하기
blog/forms.py
파일에 CommentForm
클래스를 추가해주세요:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('author', 'text',)
이 폼은 Comment
모델을 기반으로 하며, author
와 text
필드만 포함해요.
11.4 댓글 관련 뷰 추가하기
blog/views.py
파일에 댓글 관련 뷰 함수를 추가해주세요:
from .models import Post, Comment
from .forms import PostForm, CommentForm
# post_detail 함수 수정
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
comments = post.comments.filter(approved=True).order_by('-created_date')
if request.method == "POST":
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post = post
comment.save()
return redirect('blog:post_detail', pk=post.pk)
else:
comment_form = CommentForm()
return render(request, 'blog/post_detail.html', {
'post': post,
'comments': comments,
'comment_form': comment_form
})
def comment_approve(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.approve()
return redirect('blog:post_detail', pk=comment.post.pk)
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
post_pk = comment.post.pk
comment.delete()
return redirect('blog:post_detail', pk=post_pk)
이 코드는 다음과 같은 기능을 추가해요:
- 🔸 post_detail: 게시물 상세 페이지에서 댓글 목록을 표시하고 새 댓글을 추가할 수 있는 기능
- 🔸 comment_approve: 댓글을 승인하는 기능
- 🔸 comment_remove: 댓글을 삭제하는 기능
11.5 URL 패턴 추가하기
blog/urls.py
파일에 댓글 관련 URL 패턴을 추가해주세요:
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<pk>/edit/', views.post_edit, name='post_edit'),
path('comment/<pk>/approve/', views.comment_approve, name='comment_approve'),
path('comment/<pk>/remove/', views.comment_remove, name='comment_remove'),
]</pk></pk></pk></pk>
11.6 댓글 표시 템플릿 수정하기
blog/templates/blog/post_detail.html
파일을 수정해서 댓글 목록과 댓글 폼을 추가해주세요:
{% extends 'blog/base.html' %}
{% block content %}
<article class="my-4">
<h1>{{ post.title }}</h1>
<p class="text-muted">
Published on {{ post.published_date }} by {{ post.author }}
</p>
<div class="my-4">
{{ post.content|linebreaks }}
</div>
<div class="mt-4">
<a href="{% url 'blog:post_edit' pk=post.pk %}" class="btn btn-secondary">Edit post</a>
<a href="{% url 'blog:post_list' %}" class="btn btn-outline-primary">Back to list</a>
</div>
</article>
<section class="my-5">
<h2>Comments ({{ comments|length }})</h2>
{% for comment in comments %}
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">{{ comment.author }}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{ comment.created_date }}</h6>
<p class="card-text">{{ comment.text|linebreaks }}</p>
<a href="{% url 'blog:comment_remove' pk=comment.pk %}" class="card-link text-danger">Delete</a>
</div>
</div>
{% empty %}
<div class="alert alert-info">No comments yet. Be the first to comment!</div>
{% endfor %}
<div class="card mt-4">
<div class="card-header">Add a comment</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label for="id_author" class="form-label">Your name</label>
{{ comment_form.author.errors }}
<input type="text" name="author" id="id_author" class="form-control" required>
</div>
<div class="mb-3">
<label for="id_text" class="form-label">Comment</label>
{{ comment_form.text.errors }}
<textarea name="text" id="id_text" class="form-control" rows="3" required></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</section>
{% endblock %}
이 템플릿은 게시물 아래에 댓글 목록과 새 댓글을 추가할 수 있는 폼을 표시해요.
11.7 관리자 페이지에 댓글 모델 등록하기
blog/admin.py
파일에 Comment
모델을 등록해주세요:
from django.contrib import admin
from .models import Post, Comment
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'created_date', 'published_date')
list_filter = ('created_date', 'published_date', 'author')
search_fields = ('title', 'content')
date_hierarchy = 'created_date'
ordering = ('-created_date',)
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ('author', 'post', 'created_date', 'approved')
list_filter = ('approved', 'created_date')
search_fields = ('author', 'text')
actions = ['approve_comments']
def approve_comments(self, request, queryset):
queryset.update(approved=True)
approve_comments.short_description = "Approve selected comments"
이 코드는 Comment
모델을 관리자 페이지에 등록하고, 댓글을 일괄 승인할 수 있는 액션을 추가해요.
이제 댓글 기능이 완성됐어요! 개발 서버를 실행하고 게시물에 댓글을 추가해보세요!
12. 사용자 인증 구현하기 🔐
지금까지는 누구나 게시물을 작성하고 수정할 수 있었어요. 하지만 실제 블로그에서는 로그인한 사용자만 게시물을 작성하고 수정할 수 있어야 해요. 이제 사용자 인증 기능을 구현해볼게요!
12.1 로그인 폼 만들기
blog/forms.py
파일에 로그인 폼을 추가해주세요:
from django.contrib.auth.forms import AuthenticationForm
class LoginForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Username'})
self.fields['password'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Password'})
이 코드는 Django의 기본 AuthenticationForm
을 상속받아 Bootstrap 스타일을 적용한 로그인 폼을 정의해요.
12.2 로그인/로그아웃 뷰 추가하기
blog/views.py
파일에 로그인/로그아웃 뷰를 추가해주세요:
from django.contrib.auth import login, logout
from django.contrib.auth.decorators import login_required
from .forms import PostForm, CommentForm, LoginForm
def login_view(request):
if request.method == 'POST':
form = LoginForm(request, data=request.POST)
if form.is_valid():
user = form.get_user()
login(request, user)
return redirect('blog:post_list')
else:
form = LoginForm()
return render(request, 'blog/login.html', {'form': form})
def logout_view(request):
logout(request)
return redirect('blog:post_list')
이 코드는 로그인과 로그아웃 기능을 처리하는 뷰 함수를 정의해요.
12.3 로그인 필요한 뷰에 데코레이터 추가하기
게시물 생성과 수정 뷰에 @login_required
데코레이터를 추가해주세요:
@login_required
def post_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('blog:post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
@login_required
def post_edit(request, pk):
post = get_object_or_404(Post, pk=pk)
if post.author != request.user:
return redirect('blog:post_detail', pk=post.pk)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('blog:post_detail', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'blog/post_edit.html', {'form': form})
@login_required
데코레이터는 로그인하지 않은 사용자가 해당 뷰에 접근하려고 하면 로그인 페이지로 리다이렉트해요. 또한 post_edit
함수에는 게시물 작성자만 수정할 수 있도록 권한 검사 코드를 추가했어요.
12.4 URL 패턴 추가하기
blog/urls.py
파일에 로그인/로그아웃 URL 패턴을 추가해주세요:
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<pk>/edit/', views.post_edit, name='post_edit'),
path('comment/<pk>/approve/', views.comment_approve, name='comment_approve'),
path('comment/<pk>/remove/', views.comment_remove, name='comment_remove'),
path('login/', views.login_view, name='login'),
path('logout/', views.logout_view, name='logout'),
]</pk></pk></pk></pk>
12.5 로그인 템플릿 만들기
blog/templates/blog/login.html
파일을 만들고 다음 코드를 작성해주세요:
{% extends 'blog/base.html' %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card mt-5">
<div class="card-header">
<h2 class="text-center">Log in</h2>
</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label for="id_username" class="form-label">Username</label>
{{ form.username.errors }}
{{ form.username }}
</div>
<div class="mb-3">
<label for="id_password" class="form-label">Password</label>
{{ form.password.errors }}
{{ form.password }}
</div>
{% if form.non_field_errors %}
<div class="alert alert-danger">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
<div class="d-grid">
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
12.6 네비게이션 바 수정하기
base.html
파일의 네비게이션 바를 수정해서 로그인 상태에 따라 다른 메뉴를 표시해주세요:
<header class="blog-header py-3 mb-4 border-bottom">
<div class="container d-flex flex-wrap justify-content-center">
<a href="{% url 'blog:post_list' %}" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
<span class="fs-4 blog-title">Django Blog</span>
</a>
<ul class="nav nav-pills">
<li class="nav-item"><a href="{% url 'blog:post_list' %}" class="nav-link text-white">Home</a></li>
{% if user.is_authenticated %}
<li class="nav-item"><a href="{% url 'blog:post_new' %}" class="nav-link text-white">New Post</a></li>
<li class="nav-item"><a href="{% url 'blog:logout' %}" class="nav-link text-white">Logout ({{ user.username }})</a></li>
{% else %}
<li class="nav-item"><a href="{% url 'blog:login' %}" class="nav-link text-white">Login</a></li>
{% endif %}
</ul>
</div>
</header>
{% if user.is_authenticated %}
조건문을 사용해서 로그인한 사용자에게는 "New Post"와 "Logout" 메뉴를, 로그인하지 않은 사용자에게는 "Login" 메뉴를 표시해요.
12.7 로그인 URL 설정하기
mywebsite/settings.py
파일에 로그인 URL을 설정해주세요:
LOGIN_URL = 'blog:login'
이 설정은 @login_required
데코레이터가 로그인하지 않은 사용자를 리다이렉트할 URL을 지정해요.
💡 꿀팁!
더 완벽한 사용자 인증 시스템을 구현하려면 회원가입, 비밀번호 재설정, 이메일 인증 등의 기능을 추가할 수 있어요. Django의 django-allauth
같은 패키지를 사용하면 이런 기능을 쉽게 구현할 수 있어요!
13. 배포 준비하기 🚀
지금까지는 개발 환경에서 Django 앱을 실행했어요. 하지만 실제 사용자들이 웹사이트에 접속할 수 있게 하려면 인터넷에 배포해야 해요. 이번에는 배포를 위한 준비 과정을 알아볼게요.
13.1 환경 변수 설정하기
프로덕션 환경에서는 비밀 키나 데이터베이스 정보 같은 민감한 정보를 코드에 직접 포함시키지 않는 것이 좋아요. 대신 환경 변수를 사용해볼게요.
먼저 python-dotenv
패키지를 설치해주세요:
pip install python-dotenv
프로젝트 루트 디렉토리에 .env
파일을 만들고 다음과 같이 작성해주세요:
DEBUG=True
SECRET_KEY=your-secret-key
DATABASE_URL=sqlite:///db.sqlite3
그리고 mywebsite/settings.py
파일을 수정해서 환경 변수를 사용하도록 해주세요:
import os
from pathlib import Path
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('SECRET_KEY', 'django-insecure-default-key')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
이제 .env
파일을 .gitignore
파일에 추가해서 Git 저장소에 포함되지 않도록 해주세요:
# .gitignore
.env
*.pyc
__pycache__/
db.sqlite3
13.2 정적 파일 수집하기
프로덕션 환경에서는 Django가 직접 정적 파일을 제공하지 않아요. 대신 Nginx나 Apache 같은 웹 서버가 정적 파일을 제공해요. 이를 위해 정적 파일을 한 곳에 수집해야 해요.
mywebsite/settings.py
파일에 다음 설정을 추가해주세요:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles')
그리고 다음 명령어를 실행해서 정적 파일을 수집해주세요:
python manage.py collectstatic
이 명령어는 모든 앱의 정적 파일을 staticfiles
디렉토리에 복사해요.
13.3 데이터베이스 설정하기
프로덕션 환경에서는 SQLite 대신 PostgreSQL이나 MySQL 같은 더 강력한 데이터베이스를 사용하는 것이 좋아요. 여기서는 PostgreSQL을 사용하는 방법을 알아볼게요.
먼저 psycopg2
패키지를 설치해주세요:
pip install psycopg2-binary
그리고 mywebsite/settings.py
파일의 DATABASES
설정을 수정해주세요:
import dj_database_url
DATABASES = {
'default': dj_database_url.config(
default=os.getenv('DATABASE_URL', 'sqlite:///db.sqlite3'),
conn_max_age=600
)
}
이 설정은 DATABASE_URL
환경 변수에 지정된 데이터베이스를 사용해요. 환경 변수가 없으면 기본값으로 SQLite를 사용해요.
13.4 WSGI 서버 설정하기
프로덕션 환경에서는 Django의 개발 서버 대신 Gunicorn이나 uWSGI 같은 WSGI 서버를 사용해요. 여기서는 Gunicorn을 사용하는 방법을 알아볼게요.
먼저 gunicorn
패키지를 설치해주세요:
pip install gunicorn
Gunicorn으로 Django 앱을 실행하려면 다음 명령어를 사용해요:
gunicorn mywebsite.wsgi:application
13.5 requirements.txt 파일 생성하기
프로젝트에 필요한 모든 패키지를 requirements.txt
파일에 기록해두면 다른 환경에서도 쉽게 설치할 수 있어요. 다음 명령어를 실행해서 requirements.txt
파일을 생성해주세요:
pip freeze > requirements.txt
13.6 배포 플랫폼 선택하기
Django 앱을 배포할 수 있는 다양한 플랫폼이 있어요:
- 🔹 Heroku: 간단한 배포 과정, 무료 티어 제공
- 🔹 PythonAnywhere: Python 특화 호스팅, 무료 티어 제공
- 🔹 AWS: 확장성이 뛰어나지만 설정이 복잡함
- 🔹 DigitalOcean: 저렴한 VPS 제공, 자유도가 높음
- 🔹 Vercel: 정적 사이트와 서버리스 함수에 최적화
각 플랫폼마다 배포 방법이 다르지만, 대부분 Git 저장소를 연결하고 환경 변수를 설정하는 과정이 포함돼요.
💡 꿀팁!
배포 과정을 자동화하려면 GitHub Actions나 GitLab CI/CD 같은 CI/CD 도구를 사용하는 것이 좋아요. 이런 도구를 사용하면 코드를 푸시할 때마다 자동으로 테스트를 실행하고 배포할 수 있어요!
14. 마무리 및 다음 단계 🎯
축하합니다! 🎉 여러분은 Django를 사용해서 완전한 블로그 웹 애플리케이션을 만들었어요. 이 과정에서 Django의 기본 개념과 웹 개발의 핵심 요소들을 배웠어요.
14.1 배운 내용 정리
이 튜토리얼에서 다룬 내용을 정리해볼게요:
- Django 프로젝트와 앱 생성하기
- 모델 정의하고 데이터베이스 마이그레이션 실행하기
- 관리자 페이지 사용하기
- URL 패턴 설정하기
- 뷰 함수 작성하기
- 템플릿 만들기
- 정적 파일 관리하기
- 폼 처리하기
- 사용자 인증 구현하기
- 배포 준비하기
14.2 다음 단계
Django를 더 깊이 배우고 싶다면 다음 주제들을 공부해보세요:
- 🔸 클래스 기반 뷰: 함수 기반 뷰보다 더 강력하고 재사용 가능한 뷰를 작성할 수 있어요.
- 🔸 REST API: Django REST Framework를 사용해서 API를 만들 수 있어요.
- 🔸 비동기 작업: Celery를 사용해서 비동기 작업을 처리할 수 있어요.
- 🔸 테스트: Django의 테스트 프레임워크를 사용해서 코드의 품질을 보장할 수 있어요.
- 🔸 캐싱: Redis나 Memcached를 사용해서 성능을 향상시킬 수 있어요.
- 🔸 보안: CSRF, XSS, SQL 인젝션 같은 보안 취약점을 방지하는 방법을 배울 수 있어요.
14.3 유용한 리소스
Django를 더 배우는 데 도움이 될 만한 리소스들이에요:
- 🔹 Django 공식 문서: 가장 신뢰할 수 있는 정보 소스예요.
- 🔹 Django 커뮤니티: 질문하고 도움을 받을 수 있는 곳이에요.
- 🔹 Django GitHub 저장소: 소스 코드를 살펴보고 기여할 수 있어요.
- 🔹 Django Packages: 유용한 Django 패키지를 찾을 수 있어요.
- 🔹 재능넷: 다양한 개발자들의 재능을 만나볼 수 있는 플랫폼이에요. Django 개발 관련 도움을 받을 수도 있어요!
Django는 정말 강력하고 유연한 웹 프레임워크예요. 이 튜토리얼은 Django의 기본 기능만 다뤘지만, 여러분이 더 많은 것을 배우고 멋진 웹 애플리케이션을 만들 수 있는 발판이 되었으면 좋겠어요!
여러분의 Django 여정이 즐겁고 보람찬 경험이 되길 바랍니다! 화이팅! 💪
이 튜토리얼이 도움이 되셨나요?
재능넷에서 더 많은 개발 관련 지식과 튜토리얼을 찾아보세요! 또한 Django 개발에 도움이 필요하시다면, 재능넷에서 전문 개발자들의 도움을 받을 수 있어요. 함께 성장하는 개발 커뮤니티에 참여해보세요! 😊
1. Django란 무엇인가요? 🤔
Django(장고)는 Python으로 작성된 오픈 소스 웹 프레임워크예요. 2005년에 처음 출시된 이후로 계속 발전해왔고, 2025년 현재 Django 5.1 버전까지 나왔어요! 인스타그램, 핀터레스트, 모질라 같은 대형 서비스들도 Django로 만들어졌다는 거 알고 계셨나요? 대박이죠? 😲
Django의 철학은 "Don't Repeat Yourself" (DRY)와 "Batteries Included"예요. 코드 재사용을 장려하고, 웹 개발에 필요한 대부분의 기능이 이미 내장되어 있어요. 그래서 개발자들이 비즈니스 로직에 집중할 수 있게 해준답니다!
Django는 MTV(Model-Template-View) 패턴을 사용해요. 이건 MVC(Model-View-Controller) 패턴과 비슷한데, 이름만 좀 다르게 부르는 거예요.
- 🔹 Model: 데이터베이스와 상호작용하는 부분
- 🔹 Template: 사용자에게 보여지는 HTML 부분
- 🔹 View: 비즈니스 로직을 처리하는 부분
이제 Django가 뭔지 대충 감이 오시죠? 그럼 바로 실전으로 들어가볼게요! 🏃♂️
2. 개발 환경 설정하기 ⚙️
Django로 개발하기 전에 필요한 것들을 설치해볼게요. 진짜 별거 없어요! 파이썬이랑 Django만 있으면 됩니다!
2.1 Python 설치하기
Django는 Python으로 만들어졌기 때문에 당연히 Python이 필요해요. 2025년 3월 기준으로 Python 3.12 이상을 추천해요.
Python 설치는 Python 공식 웹사이트에서 할 수 있어요. 설치할 때 'Add Python to PATH' 옵션을 꼭 체크해주세요! 안 그러면 나중에 머리 아파요... ㅋㅋㅋ
2.2 가상환경 만들기
가상환경이 뭐냐고요? 쉽게 말하면 프로젝트마다 별도의 "방"을 만들어서 각 프로젝트에 필요한 라이브러리들이 서로 충돌하지 않게 해주는 거예요. 진짜 필수입니다! 안 그러면 나중에 프로젝트 여러 개 하다가 대환장 파티 열려요... 😱
터미널(맥/리눅스) 또는 명령 프롬프트(윈도우)를 열고 다음 명령어를 입력해볼게요:
# 가상환경 생성하기
python -m venv django_env
# 가상환경 활성화하기 (윈도우)
django_env\Scripts\activate
# 가상환경 활성화하기 (맥/리눅스)
source django_env/bin/activate
가상환경이 활성화되면 터미널 앞에 (django_env)
같은 표시가 나타나요. 이제 이 "방" 안에서 Django를 설치할 준비가 됐어요!
2.3 Django 설치하기
이제 진짜 Django를 설치해볼게요. pip라는 파이썬 패키지 관리자를 사용할 거예요:
# Django 최신 버전 설치하기
pip install django
2025년 3월 기준으로 Django 5.1 버전이 설치될 거예요. 설치가 완료되면 다음 명령어로 제대로 설치됐는지 확인해볼까요?
python -m django --version
버전 번호가 나오면 성공이에요! 🎉 이제 Django 프로젝트를 시작할 준비가 됐어요!
💡 꿀팁!
개발할 때 도움이 되는 추가 도구들도 설치해보세요:
- VS Code: 무료 코드 에디터로 Django 개발에 딱이에요!
- Django Extensions:
pip install django-extensions
로 설치하면 개발할 때 유용한 기능들을 추가해줘요. - Django Debug Toolbar:
pip install django-debug-toolbar
로 설치하면 디버깅이 훨씬 쉬워져요.
3. 첫 번째 Django 프로젝트 만들기 🎬
자, 이제 진짜 Django 프로젝트를 만들어볼게요! 너무 설레지 않나요? ㅋㅋㅋ
3.1 프로젝트 생성하기
Django에는 프로젝트를 쉽게 시작할 수 있는 명령어가 있어요. 터미널에서 다음 명령어를 입력해보세요:
django-admin startproject mywebsite
이 명령어는 mywebsite
라는 이름의 Django 프로젝트를 생성해요. 물론 여러분이 원하는 이름으로 바꿔도 돼요! 'coolproject', 'awesome_blog' 뭐 이런 식으로요. 근데 공백이나 특수문자는 쓰지 마세요! 파이썬이 싫어해요... 😅
3.2 프로젝트 구조 살펴보기
프로젝트가 생성되면 다음과 같은 구조가 만들어져요:
mywebsite/
├── manage.py
└── mywebsite/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
각 파일의 역할을 간단히 설명해드릴게요:
- 🔸 manage.py: Django 프로젝트를 관리하는 명령행 유틸리티
- 🔸 __init__.py: 이 디렉토리가 파이썬 패키지임을 알려주는 빈 파일
- 🔸 settings.py: 프로젝트의 설정을 담고 있는 파일 (진짜 중요!)
- 🔸 urls.py: URL 패턴을 정의하는 파일
- 🔸 asgi.py: ASGI 호환 웹 서버를 위한 진입점
- 🔸 wsgi.py: WSGI 호환 웹 서버를 위한 진입점
처음에는 이게 다 뭔지 몰라도 괜찮아요! 저도 처음에는 몰랐어요... ㅋㅋㅋ 하나씩 알아가면 돼요!
3.3 개발 서버 실행하기
이제 Django의 개발 서버를 실행해볼게요. 이 서버는 개발 중에만 사용하는 간단한 웹 서버예요. 프로젝트 폴더로 이동해서 다음 명령어를 실행해보세요:
cd mywebsite
python manage.py runserver
터미널에 다음과 비슷한 메시지가 나타날 거예요:
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
March 17, 2025 - 15:50:53
Django version 5.1, using settings 'mywebsite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
이제 웹 브라우저를 열고 http://127.0.0.1:8000으로 접속해보세요. 짜잔! 🎉 Django의 환영 페이지가 보일 거예요!
축하합니다! 🎊 여러분의 첫 번째 Django 프로젝트가 실행됐어요! 아직은 빈 프로젝트지만, 이제부터 하나씩 채워나갈 거예요!
⚠️ 주의사항
터미널에 나온 마이그레이션 경고는 무시하지 마세요! 다음 단계에서 해결할 거예요. 마이그레이션은 데이터베이스 구조를 변경하는 Django의 방식이에요.
4. Django 앱 생성하기 📱
Django에서는 프로젝트를 여러 개의 "앱(App)"으로 나눠서 관리해요. 앱은 특정 기능을 담당하는 모듈이라고 생각하면 돼요. 예를 들어, 블로그 프로젝트라면 'posts', 'comments', 'users' 같은 앱들로 나눌 수 있어요.
4.1 앱 생성하기
우리는 간단한 블로그 앱을 만들어볼게요. 터미널에서 다음 명령어를 실행해보세요:
python manage.py startapp blog
이 명령어는 blog
라는 이름의 앱을 생성해요. 이제 프로젝트 구조가 다음과 같이 변경됐을 거예요:
mywebsite/
├── blog/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations/
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
└── mywebsite/
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
각 파일의 역할을 간단히 설명해드릴게요:
- 🔹 admin.py: 관리자 페이지 설정
- 🔹 apps.py: 앱 설정
- 🔹 migrations/: 데이터베이스 변경사항 관리
- 🔹 models.py: 데이터 모델 정의
- 🔹 tests.py: 테스트 코드 작성
- 🔹 views.py: 뷰 함수 정의
4.2 앱 등록하기
앱을 만들었으면 Django에게 이 앱을 사용할 거라고 알려줘야 해요. mywebsite/settings.py
파일을 열고 INSTALLED_APPS
리스트에 우리가 만든 앱을 추가해주세요:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # 우리가 만든 앱 추가
]
4.3 데이터베이스 마이그레이션 실행하기
앞서 개발 서버를 실행했을 때 마이그레이션 관련 경고가 나왔죠? 이제 그 문제를 해결해볼게요. 마이그레이션은 Django가 데이터베이스 스키마를 관리하는 방법이에요.
python manage.py migrate
이 명령어를 실행하면 Django가 기본 앱들에 필요한 데이터베이스 테이블을 생성해요. 터미널에 여러 줄의 "OK"가 표시되면 성공한 거예요!
💡 꿀팁!
Django는 기본적으로 SQLite 데이터베이스를 사용해요. 이건 파일 기반 데이터베이스라서 별도의 설치 없이 바로 사용할 수 있어요. 실제 서비스에서는 PostgreSQL이나 MySQL 같은 더 강력한 데이터베이스를 사용하는 게 좋아요!
5. 모델 설계하기 📊
이제 블로그 앱의 데이터 모델을 설계해볼게요. 모델은 데이터베이스의 구조를 정의하는 부분이에요. 블로그니까 당연히 "게시물(Post)" 모델이 필요하겠죠?
5.1 모델 정의하기
blog/models.py
파일을 열고 다음과 같이 수정해주세요:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
이 코드는 Post
라는 모델을 정의해요. 각 필드의 의미는 다음과 같아요:
- 🔸 title: 게시물 제목 (최대 200자)
- 🔸 content: 게시물 내용 (텍스트)
- 🔸 created_date: 게시물 생성 날짜 (자동으로 현재 시간 설정)
- 🔸 published_date: 게시물 발행 날짜 (선택적)
- 🔸 author: 게시물 작성자 (User 모델과 연결)
또한 두 개의 메서드도 정의했어요:
- 🔸 publish(): 게시물을 발행하는 메서드
- 🔸 __str__(): 객체를 문자열로 표현할 때 사용하는 메서드
5.2 모델 마이그레이션 생성하기
모델을 정의했으니 이제 이 모델에 맞는 데이터베이스 테이블을 생성해야 해요. Django의 마이그레이션 시스템을 사용해서 모델 변경사항을 데이터베이스에 적용할 수 있어요.
python manage.py makemigrations blog
이 명령어는 blog
앱의 모델 변경사항을 감지하고 마이그레이션 파일을 생성해요. 터미널에 다음과 비슷한 메시지가 나타날 거예요:
Migrations for 'blog':
blog/migrations/0001_initial.py
- Create model Post
5.3 마이그레이션 적용하기
이제 생성된 마이그레이션을 데이터베이스에 적용해볼게요:
python manage.py migrate blog
이 명령어는 blog
앱의 마이그레이션을 데이터베이스에 적용해요. 터미널에 "OK"가 표시되면 성공한 거예요!
축하합니다! 이제 데이터베이스에 블로그 게시물을 저장할 수 있는 테이블이 생성됐어요! 다음 단계에서는 이 모델을 관리자 페이지에 등록해서 쉽게 관리할 수 있게 만들어볼게요.
6. 관리자 페이지 사용하기 👨💼
Django의 가장 강력한 기능 중 하나는 자동으로 생성되는 관리자 페이지예요. 이 페이지를 통해 모델 데이터를 쉽게 관리할 수 있어요. 진짜 개발자들이 엄청 좋아하는 기능이에요! ㅋㅋㅋ
6.1 관리자 계정 생성하기
관리자 페이지에 접속하려면 먼저 관리자 계정을 생성해야 해요. 다음 명령어를 실행해보세요:
python manage.py createsuperuser
이 명령어를 실행하면 사용자 이름, 이메일 주소, 비밀번호를 입력하라는 메시지가 나타나요. 원하는 정보를 입력하고 계정을 생성해주세요. 비밀번호는 보안을 위해 화면에 표시되지 않아요!
6.2 모델을 관리자 페이지에 등록하기
이제 Post
모델을 관리자 페이지에 등록해볼게요. blog/admin.py
파일을 열고 다음과 같이 수정해주세요:
from django.contrib import admin
from .models import Post
admin.site.register(Post)
이 코드는 Post
모델을 관리자 페이지에 등록해요. 이제 관리자 페이지에서 게시물을 생성, 수정, 삭제할 수 있어요!
6.3 관리자 페이지 접속하기
개발 서버를 실행하고 관리자 페이지에 접속해볼게요:
python manage.py runserver
웹 브라우저에서 http://127.0.0.1:8000/admin/으로 접속하면 로그인 페이지가 나타나요. 앞서 생성한 관리자 계정으로 로그인해보세요.
로그인하면 관리자 대시보드가 나타나요. 여기서 "Posts" 링크를 클릭하면 게시물 목록 페이지로 이동해요. "Add Post" 버튼을 클릭해서 새 게시물을 생성해보세요!
6.4 관리자 페이지 커스터마이징
기본 관리자 페이지도 좋지만, 더 사용하기 편하게 커스터마이징할 수도 있어요. blog/admin.py
파일을 다음과 같이 수정해보세요:
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'created_date', 'published_date')
list_filter = ('created_date', 'published_date', 'author')
search_fields = ('title', 'content')
date_hierarchy = 'created_date'
ordering = ('-created_date',)
이 코드는 Post
모델의 관리자 페이지를 다음과 같이 커스터마이징해요:
- 🔹 list_display: 목록 페이지에 표시할 필드
- 🔹 list_filter: 필터링 옵션
- 🔹 search_fields: 검색 가능한 필드
- 🔹 date_hierarchy: 날짜 기반 탐색
- 🔹 ordering: 정렬 방식 (- 기호는 내림차순)
개발 서버를 다시 실행하고 관리자 페이지에 접속해보세요. 훨씬 더 사용하기 편해졌죠? 😎
💡 꿀팁!
관리자 페이지는 개발 중에 데이터를 관리하기 좋은 도구지만, 실제 사용자들이 사용할 인터페이스는 아니에요. 다음 단계에서는 사용자들이 볼 수 있는 페이지를 만들어볼게요!
7. URL 설정하기 🔗
이제 사용자들이 웹사이트에 접속했을 때 볼 수 있는 페이지를 만들어볼게요. Django에서는 URL 패턴을 정의해서 특정 URL에 접속했을 때 어떤 뷰 함수를 실행할지 결정해요.
7.1 앱 URL 설정 파일 생성하기
먼저 blog
앱에 URL 설정 파일을 생성해볼게요. blog
디렉토리 안에 urls.py
파일을 생성하고 다음 코드를 작성해주세요:
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<pk>/edit/', views.post_edit, name='post_edit'),
]</pk></pk>
이 코드는 다음과 같은 URL 패턴을 정의해요:
- 🔸 /: 게시물 목록 페이지
- 🔸 /post/1/: ID가 1인 게시물의 상세 페이지
- 🔸 /post/new/: 새 게시물 작성 페이지
- 🔸 /post/1/edit/: ID가 1인 게시물의 수정 페이지
각 URL 패턴은 해당하는 뷰 함수와 연결되어 있어요. 아직 이 뷰 함수들을 작성하지 않았지만, 곧 작성할 거예요!
7.2 프로젝트 URL 설정에 앱 URL 포함시키기
이제 프로젝트의 메인 URL 설정 파일에 앱의 URL 설정을 포함시켜야 해요. mywebsite/urls.py
파일을 열고 다음과 같이 수정해주세요:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
이 코드는 루트 URL('/')에 접속했을 때 blog.urls
에 정의된 URL 패턴을 사용하도록 설정해요. 이제 사용자가 웹사이트에 접속하면 블로그 앱의 페이지가 표시될 거예요!
URL 패턴을 정의했으니 이제 뷰 함수를 작성해볼게요!
- 지식인의 숲 - 지적 재산권 보호 고지
지적 재산권 보호 고지
- 저작권 및 소유권: 본 컨텐츠는 재능넷의 독점 AI 기술로 생성되었으며, 대한민국 저작권법 및 국제 저작권 협약에 의해 보호됩니다.
- AI 생성 컨텐츠의 법적 지위: 본 AI 생성 컨텐츠는 재능넷의 지적 창작물로 인정되며, 관련 법규에 따라 저작권 보호를 받습니다.
- 사용 제한: 재능넷의 명시적 서면 동의 없이 본 컨텐츠를 복제, 수정, 배포, 또는 상업적으로 활용하는 행위는 엄격히 금지됩니다.
- 데이터 수집 금지: 본 컨텐츠에 대한 무단 스크래핑, 크롤링, 및 자동화된 데이터 수집은 법적 제재의 대상이 됩니다.
- AI 학습 제한: 재능넷의 AI 생성 컨텐츠를 타 AI 모델 학습에 무단 사용하는 행위는 금지되며, 이는 지적 재산권 침해로 간주됩니다.
재능넷은 최신 AI 기술과 법률에 기반하여 자사의 지적 재산권을 적극적으로 보호하며,
무단 사용 및 침해 행위에 대해 법적 대응을 할 권리를 보유합니다.
© 2025 재능넷 | All rights reserved.
댓글 0개