Python Django를 공부하며 기록해둔 것들을 포스팅합니다.
실무에서 바로 사용할 수 있도록 기록하였습니다.
⭐ MTV 패턴#
- Model : DB와의 상호작용을 담당하며 데이터의 구조를 정의
- Template : 사용자에게 보여지는 HTML 등의 출력물을 생성
- View : 비즈니스 로직을 처리하고 Model과 Template 간의 연결을 관리
⭐ 설치#
프로젝트 : myblog
앱(서비스) : post
1. venv 세팅#
# .venv 외 원하는 이름 사용 가능
python3 -m venv .venv
source .venv/bin/activate
2. Django 설치#
venv 활성화 상태
pip install django~=3.2.10
3. 프로젝트 생성#
myblog 프로젝트 디렉토리가 생성됩니다.
django-admin startproject myblog .
4. 앱 추가#
post 디렉토리가 생성됩니다.
python manage.py startapp mypost
5. 앱 시작#
python manage.py runserver
⭐ 설정#
1. [ myblog/settings.py ]#
앱 등록#
생성한 앱을 INSTALLED_APPS 에 등록해주어야 정상 작동합니다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'mypost' # 앱 추가
]
...
TIME_ZONE = 'Asia/Seoul' # 시간대 한국으로 변경
디버깅 모드 설정#
배포 시에는 False로 설정해야 합니다. (에러 내용 노출 방지)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
접근 제한 설정#
허용 가능한 호스트는 운영 서버 등에 배포하여, 서비스할 때 호스트로 사용 가능한 호스트 또는 도메인 목록입니다.
위 DEBUG 설정이 True 이고 ALLOWED_HOSTS 설정 값이 비어있으면 [’.localhost’, ‘127.0.0.1’, ‘[::1]’] 대상에 대해 유효성을 검증합니다.
ALLOWED_HOSTS = []
2. [ myblog/urls.py ]#
각 앱에 경로를 할당합니다. (아래는 기본 값)
urlpatterns = [
path('admin/', admin.site.urls),
]
3. 어드민 모델 마이그레이션#
어드민 기능을 사용하려면 필수 사항입니다.
python manage.py migrate
4. 어드민 계정 생성#
python manage.py createsuperuser
# pw: 1q2w3e4r! (임의 값)
⭐ Model#
앱의 모델 생성#
📄 mypost/models.py
class Mypost(models.Model):
title = models.CharField(max_length=300)
tag = models.CharField(max_length=100)
image = models.CharField(max_length=300)
summary = models.TextField()
content = models.TextField()
# 정의한 모델을 이용하여 DB 생성
python manage.py makemigrations
python manage.py migrate
앱 모델을 어드민 페이지에 적용#
📄 myblog/admin.py
from django.contrib import admin
from .models import Mypost
admin.site.register(Mypost)
⭐ Template#
📄 mypost/templates/mypost/postlist.html
<html>
<head>
<title>My blog</title>
</head>
<body>
<h1><a href="">Post list</a></h1>
<section>
<!-- posts라는 변수에 담긴 데이터(일반적으로 뷰에서 제공된 포스트 목록)를 반복함 -->
{% for post in posts %}
<div>
<!-- 각 post 객체에 포함된 이미지 경로를 출력하고, 이미지의 제목과 크기를 설정 -->
<img src="{{ post.image }}" alt="{{ post.title }}" width="300" />
<h2>
<!-- 각 post의 세부 페이지로 이동하는 링크를 생성 -->
<!-- {% url 'post_detail' pk=post.pk %}는 'post_detail'이라는 이름의 URL에 post의 pk 값을 전달하여 세부 페이지로 연결 -->
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a>
</h2>
<!-- 각 post의 태그를 출력 -->
<p>Tags : {{ post.tag }}</p>
<!-- 각 post의 요약(summary)을 출력 -->
<p>Summary : {{ post.summary }}</p>
</div>
{% endfor %}
</section>
</body>
</html>
{% for post in posts %} ... {% endfor %}
posts
는 뷰에서 템플릿으로 전달된 컨텍스트 변수로, 여러 개의 포스트 객체를 포함하고 있습니다.for
루프는posts
리스트 내의 각post
객체를 반복하며, 해당 객체의 정보를 HTML로 렌더링합니다.
{% for post in posts %} ... {% endfor %}
posts
는 뷰에서 템플릿으로 전달된 컨텍스트 변수로, 여러 개의 포스트 객체를 포함하고 있습니다.for
루프는posts
리스트 내의 각post
객체를 반복하며, 해당 객체의 정보를 HTML로 렌더링합니다.
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a>
{% url %}
태그는 주어진 뷰 이름에 해당하는 URL을 생성합니다.'post_detail'
은 URL 패턴 이름입니다.urls.py
파일에서 정의된 이름을 사용합니다.- 예를 들어
urls.py
파일에서path('post/<int:pk>/', views.post_detail, name='post_detail')
와 같이 정의된 경우,post_detail
이름을 사용하여 해당 URL을 참조할 수 있습니다. pk
라는 URL 파라미터는urls.py
와views.py
에서 정수(<int:pk>
)로 지정되어 있으며, 템플릿에서pk=post.pk
로 전달된 값이 이 자리에 들어가게 됩니다.pk=post.pk
: 포스트 객체의 Primary Key인pk
를 해당 URL 패턴에 전달하여, 특정 포스트의 세부 정보를 조회할 수 있도록 URL을 생성합니다.
- 예를 들어
⭐ View#
📄 mypost/forms.py
from django import forms
from .models import Mypost
class MypostForm(forms.ModelForm):
# Meta 클래스는 폼에 대한 메타데이터를 정의하는 내부 클래스
class Meta:
# 사용할 모델을 Mypost로 지정
model = Mypost
# 폼에서 사용자에게 입력받을 필드를 나열
fields = ('title', 'tag', 'image', 'summary', 'content')
MypostForm
클래스는ModelForm
을 상속받아 Django의 모델과 연관된 폼을 생성합니다. 여기서는Mypost
모델을 기반으로 사용자가title
,tag
,image
,summary
,content
필드를 입력할 수 있는 폼을 정의합니다.ModelForm
은 폼에서 입력받은 데이터를 바로 모델 인스턴스에 매핑하고, 저장할 수 있는 기능을 제공합니다.fields
에 나열된 필드들만 사용자로부터 입력받을 수 있도록 폼에 포함됩니다.
📄 mypost/views.py
from django.shortcuts import render, redirect
from .models import Mypost
from .forms import MypostForm
# 1. 게시물 목록을 보여주는 뷰 함수
def post_list(request):
# Mypost 모델의 모든 객체를 가져와서 'posts' 변수에 저장
posts = Mypost.objects.all()
# 'posts' 데이터를 'mypost/post_list.html' 템플릿에 전달하고 렌더링
return render(request, 'mypost/post_list.html', {'posts': posts})
# 2. 게시물 상세 정보를 보여주는 뷰 함수
def post_detail(request, pk):
# 주어진 pk(Primary Key)를 사용하여 특정 Mypost 객체를 가져옴
post = Mypost.objects.get(id=pk)
# 'post' 객체를 'mypost/post_detail.html' 템플릿에 전달하여 렌더링
return render(request, 'mypost/post_detail.html', {'post': post})
# 3. 게시물을 업로드하는 뷰 함수
def post_upload(request):
# 3-1. 사용자가 폼을 제출한 경우 (POST 요청)
if request.method == "POST":
# 제출된 데이터를 바탕으로 MypostForm 인스턴스 생성
form = MypostForm(request.POST)
# 폼 데이터가 유효한지 확인
if form.is_valid():
# 폼 데이터를 저장하되, 바로 데이터베이스에 커밋하지 않고 인스턴스만 반환
post = form.save(commit=False)
# 필요한 추가 처리를 한 후 데이터베이스에 저장
post.save()
# 새로 생성된 게시물의 상세 페이지로 리디렉션
return redirect('post_list', pk=post.pk)
# 3-2. GET 요청인 경우 (사용자가 페이지에 처음 접근한 경우)
else:
# 빈 MypostForm 인스턴스를 생성하여 사용자에게 보여줌
form = MypostForm()
# 빈 폼 또는 제출된 폼을 'mypost/post_upload.html' 템플릿에 전달하여 렌더링
return render(request, 'mypost/post_upload.html', {'form': form})
...
post_list
함수- 역할:
Mypost
모델의 모든 게시물을 데이터베이스에서 조회하고, 이를 템플릿으로 전달하여 게시물 목록을 출력하는 역할을 합니다. - 작동 방식
Mypost.objects.all()
을 통해 모든 게시물을 가져옵니다.render()
함수를 사용해post_list.html
템플릿을 렌더링하고, 게시물 데이터를posts
로 전달합니다.
- 역할:
post_detail
함수- 역할: 주어진
pk
값으로 특정 게시물의 세부 정보를 조회하고, 해당 데이터를 템플릿에 전달하여 상세 페이지를 보여줍니다. - 작동 방식
Mypost.objects.get(id=pk)
로 주어진pk
에 해당하는 게시물을 조회합니다.- 조회된 게시물 객체를
post_detail.html
템플릿에 전달하여 렌더링합니다.
- 역할: 주어진
post_upload
함수- 역할: 새로운 게시물을 작성하여 업로드하는 뷰입니다.
GET
요청일 때는 빈 폼을 보여주고,POST
요청일 때는 폼 데이터를 받아 게시물을 저장합니다. - 작동 방식
- POST 요청: 사용자가 게시물 작성 폼을 제출하면,
MypostForm
을 통해 폼 데이터를 받아서 유효성 검사를 수행합니다. 검사가 통과하면form.save(commit=False)
로 폼 데이터를 바탕으로 게시물 객체를 생성하되, 데이터베이스에 바로 저장하지 않고, 추가 처리를 한 후 저장합니다. - GET 요청: 사용자가 페이지를 처음 열면 빈 폼을 렌더링합니다.
- 성공적으로 저장된 후에는, 해당 게시물의 상세 페이지로 리디렉션됩니다.
- POST 요청: 사용자가 게시물 작성 폼을 제출하면,
- 역할: 새로운 게시물을 작성하여 업로드하는 뷰입니다.