SMALL
코드 뜯어먹고 이해해보기
accounts
from django.conf import settings # Django 설정을 가져오기 위한 임포트
from django.contrib.auth.models import AbstractUser # Django 기본 User 모델을 상속하기 위한 임포트
from django.db import models # 모델 정의를 위한 임포트
class User(AbstractUser):
# AbstractUser를 상속받아 커스텀 User 모델을 정의
# Django의 기본 User 모델이 제공하는 모든 필드와 기능을 그대로 사용하면서
# 추가 필드를 정의할 수 있음
# 사용자 자기소개를 저장하는 필드
bio = models.TextField()
class Profile(models.Model):
# User 모델과 1:1 관계를 형성하는 필드
# to=settings.AUTH_USER_MODEL: 실제 User 모델을 동적으로 참조
# on_delete=models.CASCADE: 연결된 User가 삭제되면 Profile도 함께 삭제
user = models.OneToOneField(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
# 사용자의 주소를 저장하는 필드 (최대 50자)
address = models.CharField(max_length=50)
# 우편번호를 저장하는 필드 (최대 6자)
zipcode = models.CharField(max_length=6)
# Profile 모델의 문자열 표현을 정의하는 메서드
# 관리자 페이지나 print() 실행 시 address가 표시됨
def __str__(self):
return self.address
코드를 통해 알 수 있는 것
- User 모델은 Django의 AbstractUser를 상속받아 기본 인증 기능을 모두 사용하면서 bio 필드를 추가함
- Profile 모델은 User 모델과 1:1 관계를 가짐 (한 사용자는 하나의 프로필만 가질 수 있음)
- User가 삭제되면 연결된 Profile도 자동으로 삭제됨 (CASCADE)
- Profile 모델은 사용자의 주소 정보(address, zipcode)를 저장함
- 사용자의 추가 정보(주소, 우편번호)를 별도의 테이블로 관리할 수 있다
"관심사의 분리(Separation of Concerns)" 프로그래밍 원칙: User 모델은 로그인, 인증 같은 핵심 기능을 담당하고 Profile 모델은 부가적인 정보만 담당하도록 분리함으로써 코드 관리와 확장이 편리하도록 하는 것
blog
from django.db import models
from django.conf import settings
class Post(models.Model):
# 게시글 작성자를 저장하는 필드. AUTH_USER_MODEL과 1:N 관계를 형성
# CASCADE: 작성자가 삭제되면 해당 작성자의 게시글도 모두 삭제됨
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
# 게시글의 본문 내용을 저장하는 필드. 글자수 제한이 없는 텍스트 필드
message = models.TextField()
# 게시글 생성 시각을 자동으로 저장하는 필드
# auto_now_add=True: 최초 저장(생성) 시에만 현재 시간 저장
created_at = models.DateTimeField(auto_now_add=True)
# 게시글 수정 시각을 자동으로 저장하는 필드
# auto_now=True: 매번 save() 실행할 때마다 현재 시간 저장
updated_at = models.DateTimeField(auto_now=True)
# Tag 모델과 M:N(다대다) 관계를 형성하는 필드
# blank=True: 태그를 반드시 입력하지 않아도 됨(선택적 입력)
tag_set = models.ManyToManyField('Tag', blank=True)
# 해당 모델의 문자열 표현을 정의하는 메서드
# 관리자 페이지나 print() 실행 시 게시글의 message가 표시됨
def __str__(self):
return self.message
class Tag(models.Model):
# 태그명을 저장하는 필드. 최대 44자까지 저장 가능
name = models.CharField(max_length=44)
# 해당 모델의 문자열 표현을 정의하는 메서드
# 관리자 페이지나 print() 실행 시 태그의 name이 표시됨
def __str__(self):
return self.name
코드를 통해 알 수 있는 것
- User와 Post의 관계 (1:N)
- 한 사용자(User)는 여러 게시글을 작성할 수 있음
- 하나의 게시글은 단 한 명의 작성자를 가짐
- 작성자가 삭제되면 그 사람의 게시글도 모두 삭제됨
- Post와 Tag의 관계 (M:N)
- 하나의 게시글은 여러 태그를 가질 수 있음
- 하나의 태그는 여러 게시글에 사용될 수 있음
- 태그는 선택사항(blank=True)
- 시간 관리
- created_at: 게시글 작성 시간 (자동 저장)
- updated_at: 게시글 수정 시간 (수정할 때마다 자동 갱신)
from django.urls import path # URL 패턴을 정의하기 위한 path 함수를 임포트
from blog import views # blog 앱의 뷰들을 임포트
urlpatterns = [
# 루트 URL 패턴 ('/')
# route='': 아무것도 없는 경로(루트 URL)를 의미
# view=views.post_list: 해당 URL에 매핑될 뷰 함수
# name='post_list': URL 패턴의 이름. 템플릿이나 뷰에서 URL을 동적으로 생성할 때 사용
path(route='', view=views.post_list, name='post_list'),
# 새 게시글 작성 URL 패턴 ('/post_new/')
# route='post_new/': post_new/ 경로를 의미
# view=views.post_new: 해당 URL에 매핑될 뷰 함수
# name 파라미터가 생략됨 (URL Reverse 사용 불가)
path(route='post_new/', view=views.post_new,),
]
코드를 통해 알 수 있는 것
- 웹사이트의 메인 페이지('/')에 접속하면 views.post_list 함수가 실행
- '/post_new/' 경로로 접속하면 views.post_new 함수가 실행됨
- 첫 번째 패턴은 name이 지정되어 있어 템플릿에서 {% url 'post_list' %}와 같이 사용할 수 있다
from django.shortcuts import render, redirect # 템플릿 렌더링과 URL 리다이렉트를 위한 함수들
from blog.forms import PostForm # 게시글 작성을 위한 폼 클래스 임포트
from blog.models import Post # Post 모델 임포트
'''
1. view : urls 있는 주소에 매핑 확인 후 요청 처리 로직
2. 데이터 처리: 데이터베이스 핸들링(읽고, 쓰고, 수정, 삭제 등등등)
3. 응답 반환(랜더링) 템플릿
'''
def post_list(request):
# 모든 게시글 목록을 조회
posts = Post.objects.all()
# blog/post_list.html 템플릿에 posts 데이터를 전달하며 렌더링
return render(
request=request,
template_name='blog/post_list.html',
context={'posts': posts}
)
def post_new(request):
'''
POST: 사용자가 데이터를 던질 때 (폼 제출)
GET: 사용자가 페이지를 열었을 때(데이터 안 던질 때)
'''
if request.method == 'POST': # POST 요청 (폼 제출)시
# 제출된 데이터로 PostForm 인스턴스 생성
form = PostForm(request.POST)
if form.is_valid(): # 폼 유효성 검사
# commit=False: DB에 바로 저장하지 않고 객체만 생성
post = form.save(commit=False)
# request.user: 현재 로그인한 사용자 객체
post.author = request.user # 글 작성자를 현재 로그인한 사용자로 지정
post.save() # DB에 최종 저장
return redirect('post_list') # 글 목록 페이지로 리다이렉트
else: # GET 요청 (페이지 첫 로딩)시
form = PostForm() # 빈 폼 생성
# POST 요청에서 폼이 유효하지 않은 경우 or GET 요청인 경우
# 폼을 담아서 템플릿 렌더링
return render(
request=request,
template_name='blog/post_new.html',
context={'form': form}
)
코드를 통해 알 수 있는 것
1. post_list 뷰
- 모든 게시글을 조회하여 목록 페이지를 보여줌
- Post.objects.all()로 모든 게시글을 가져옴
- post_list.html 템플릿에 posts 데이터를 전달하여 렌더링
2. post_new 뷰
- GET 요청: 새 게시글 작성 폼을 보여줌
- POST 요청: 제출된 폼을 처리
- 폼 유효성 검사
- 작성자 정보 추가
- DB에 저장
- 성공 시 글 목록으로 리다이렉트
- 폼이 유효하지 않은 경우 에러와 함께 폼을 다시 보여줌
from django import forms
from blog.models import Post
'''
Forms
1. HTML 폼을 자동 생성
2. 사용자가 입력한 데이터를 검증 -> 데이터베이스 상호 작용(반영, 저장, 쓰고, 수정하거나 등등)
'''
class PostForm(forms.ModelForm): # ModelForm을 상속받음
class Meta:
model = Post # Post 모델과 연결
fields = ['message', 'tag_set'] # 입력받을 필드 지정
코드를 통해 알 수 있는 것
- 폼의 기능:
- ModelForm을 상속받아서 Post 모델과 연결된 폼을 생성
- HTML 입력 폼을 자동으로 생성해줌
- 입력된 데이터의 유효성을 검사
- 데이터베이스에 저장하는 기능 제공
- Meta 클래스:
- model = Post: Post 모델을 기반으로 폼 생성
- fields = ['message', 'tag_set']: 사용자가 입력할 수 있는 필드를 지정
- message: 게시글 내용
- tag_set: 태그 선택
<!-- --> 는 HTML의 주석 문법
<!-- 페이지 제목 -->
<h1>i hate u</h1>
<!-- 게시글 목록을 보여주는 순서 없는 리스트(unordered list) -->
<ul>
{% for post in posts %}
<!--
post: views.py의 post_list 함수에서 전달받은 게시글 객체
post.message: Post 모델의 message 필드 값을 출력
{% for %} 구문으로 posts 리스트의 각 게시글을 순회하면서 출력
-->
<li>{{ post.message }}</li>
{% endfor %}
</ul>
코드를 통해 알 수 있는 것
- 뷰에서 전달받은 모든 게시글(posts)을 반복문으로 순회
- 각 게시글(post)의 내용(message)을 리스트 아이템(<li>)으로 출력
- <ul> 태그를 사용해 순서가 없는 리스트 형태로 표시
HTML 구조:
- <h1>: 페이지의 주요 제목
- <ul>: 순서가 없는 리스트를 나타내는 컨테이너
- <li>: 리스트의 각 항목을 나타내는 태그
<!-- 새 게시글 작성 페이지의 제목 -->
<h1>post_new</h1>
<!-- 게시글 작성을 위한 폼
method="post": 데이터를 서버로 제출하는 HTTP POST 메서드 사용 -->
<form method="post">
{% csrf_token %}
<!-- CSRF(Cross Site Request Forgery) 공격을 방지하기 위한 Django의 보안 토큰 -->
{{ form.as_p }}
<!--
form: views.py에서 전달받은 PostForm 인스턴스
as_p: 각 폼 필드를 <p> 태그로 감싸서 출력
자동으로 라벨, 입력 필드, 에러 메시지 등이 생성됨
-->
<!-- 폼 제출을 위한 버튼 -->
<button type="submit">Submit</button>
</form>
코드를 통해 알 수 있는 것
- POST 메서드를 사용하여 데이터를 안전하게 서버로 전송
- CSRF 토큰을 포함하여 보안성 확보
- Django 폼 시스템을 활용하여 자동으로 HTML 폼 생성
- Submit 버튼 클릭 시 post_new 뷰의 POST 처리 로직으로 데이터 전송
실제 렌더링 시:
- form.as_p는 각 필드를 <p> 태그로 감싸서 출력
- 각 필드는 라벨, 입력창, 에러 메시지(있는 경우)를 포함
- CSRF 토큰은 hidden input 필드로 생성됨
데이터 흐름
- 사용자가 폼 작성 → Submit 클릭
- POST 요청으로 데이터 전송
- 서버에서 데이터 검증
- 성공 시 데이터베이스 저장 및 리다이렉트
LIST
'Today I learned' 카테고리의 다른 글
Djaneiro - Django Snippets 사용법 (5) | 2025.01.15 |
---|---|
2025.01.13 디제이앙고 연습 (0) | 2025.01.14 |
WIL (0) | 2025.01.10 |
Django의 관계 필드 (2) | 2025.01.09 |
2025.01.08 +99강화나무 (4) | 2025.01.08 |