학습 날짜: 2025.09.29
공부 일지 #42 | Flask & Django 실습
학습 날짜: 2025.09.22 ~ 2025.09.26🔷 Flask 학습 정리1. Bootstrap12 Grid → 한 행을 12등분한다고 생각하면 된다.Grid의 max-width → xs, sm, md, lg, xl, xxl 순으로 커진다.이미지 넣기static 디렉토리 생성이미지 파
whatistudied.tistory.com
🔷 Django 이어서
1. ImageField와 Pillow
- Django의 ImageField를 사용하면 이미지를 업로드할 수 있는 형태
- 단, 이미지를 다루려면 Pillow 라이브러리가 반드시 필요
- 터미널에 → pip install Pillow
- Pillow는 이미지를 열고, 크기 조정, 편집, 저장 등을 지원하는 라이브러리
- 업로드한 이미지는 media 폴더 안의 post 폴더에 저장되고 Django가 경로를 관리하는 구조
→ 마치 웹디스크처럼 별도 함수 없이 이미지 URL로 접근 가능.
2. Media URL 연결
- 이미지를 불러오기 위해 urls.py에 media 경로 설정 필요
# urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns += static(
prefix=settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT,
)
3. Admin에 썸네일 표시
- admin 페이지에서 Post 모델 등록 시 list_display 옵션으로 썸네일 출력 가능
# admin.py
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "thumbnail"]
4. 글 리스트에 썸네일 출력
<!-- post_list.html -->
{% for post in posts %}
<li>
<h2>{{ post.title }}</h2>
<p>{{ post.content | linebreaksbr }}</p>
<div>
{% for comment in post.comment_set.all %}
<li>{{ comment.content }}</li>
{% empty %}
<li>댓글이 없음</li>
{% endfor %}
</div>
{% if post.thumbnail %}
<img src="{{ post.thumbnail.url }}">
{% else %}
<img src=" ">
{% endif %}
</li>
<hr>
{% endfor %}
- 줄바꿈 적용을 위해 linebreaksbr 필터 사용
5. 글을 클릭하면 상세 페이지 나오게 하기
a. views.py - 상세 페이지 함수 추가
# views.py
def post_detail(request, post_id):
return render(request, "post_detail.html")
b. urls.py - 상세 페이지 링크 추가
# urls.py
urlpatterns = [
path("admin/", admin.site.urls),
path("", index),
path("posts/", post_list),
path("posts/<int:post_id>/", post_detail), # 추가!
]
c. 글 제목에 링크 연결
<!-- post_list.html -->
<h2><a href="/posts/{{ post.id }}/">{{ post.title }}</a></h2>
6. 글 작성 기능 추가
a. html 파일 생성 (post_add.html)
<!-- post_add.html -->
<form method="POST" enctype="multipart/form-data">
{% csrf_token %} <!-- 중요!! -->
<div>
<label>제목</label>
<input type="text" name="title" placeholder="제목을 입력하세요."></input>
</div><br><br>
<div>
<label>내용</label>
<textarea name = "content" cols="30" rows="10" placeholder="내용을 입력하세요."></textarea>
</div>
<div>
<label>썸네일</label>
<input type="file" name="thumbnail">
</div>
<div>
<button type="submit">작성하기</button>
</div>
</form>
- POST 요청 시 CSRF 검증이 자동 수행되므로 {% csrf_token %} 삽입 필수
- CSRF(크로스 사이트 요청 위조)? 인증된 사용자가 자신의 의지와는 무관하게 공격자가 원하는 특정 요청을 웹사이트에 보내게 만드는 보안 취약점
- 만약 생략하면, Forbidden (403), CSRF verification failed. Request aborted. 오류가 나타남.
b. views.py - 글 작성 페이지 함수 추가
- 클라이언트는 무조건 먼저 GET 방식으로 접근하는 구조
- 따라서 title = request.POST['title'] 같은 코드를 그대로 쓰면 페이지를에 접속했을 때, 값이 없어서 MultiValueDictKeyError 발생 가능성 있음
- Django에서는 GET 요청과 POST 요청을 분리해서 처리하는 방식 필요
# views.py
# 입력받은 정보를 테이블(DB)에 입력하려면, models에 있는 object(Post)의 도움을 받아야 함.
from blog.models import Post
from django.shortcuts import render, redirect
def post_add(request):
if request.method == "POST":
title = request.POST['title']
content = request.POST['content']
thumbnail = request.FILES.get("thumbnail") # 이미지 파일은 request.FILES로 처리
post = Post.objects.create(
title=title,
content=content,
thumbnail=thumbnail
) # 작성한 내용 DB에 추가
return redirect(f"/posts/{post.id}/") # 작성 후 상세 페이지로 이동, 앞뒤로 / 꼭꼭 붙여야함!!!
else:
return render(request, "post_add.html")
c. urls.py - 글 작성 페이지 링크 추가
# urls.py
urlpatterns = [
path("admin/", admin.site.urls),
path("", index),
path("index/", index),
path("posts/", post_list),
path("posts/<int:post_id>/", post_detail),
path("posts/add/", post_add) # 추가!!
]
7. 상세페이지에 댓글 기능 추가
a. 상세 페이지 html 수정
<!-- post_detail.html -->
<form method="POST">
{% csrf_token %}
<label>댓글: </label>
<textarea name = "comment" cols="40" rows="3" placeholder="내용을 입력하세요."></textarea>
<button type="submit">댓글 달기</button>
</form>
b. views.py - 상세 페이지 함수 수정
# views.py
def post_detail(request, post_id):
# SELECT * FROM blog_post WHERE id=post_id
post = Post.objects.get(id=post_id)
if request.method == "POST":
comment = request.POST['comment']
Comment.objects.create(post = post, content = comment)
context = { "post": post }
return render(request, "post_detail.html", context)
🔳 Python shell 사용하기
1. 접속 방법
- Pycharm 터미널에서
python manage.py shell
- Django의 ORM을 직접 테스트할 수 있는 인터랙티브 환경 → SQL문을 작성하지 않고 Python 코드로 DB를 조작할 수 있는 장점이 있음
2. 테스트 예시
- blog App에는 두 가지 모델(Post, Comment)이 있음
- Post 테스트: DB에 데이터가 정상적으로 들어가는지 확인하는 과정
from blog.models import Post
# 객체 생성
Post.objects.create(title="test", content="testcontent")
# 최신순 정렬
Post.objects.order_by("-id")
- Comment 테스트: ForeignKey가 없는 상태에서 Comment를 생성하면 에러가 발생하므로, post 객체와 함께 생성해야 하는 구조 확인
from blog.models import Comment, Post
# 댓글 생성 (FK 필요)
post = Post.objects.get(id=1)
Comment.objects.create(post=post, content="test comment")
# 모든 댓글 삭제
Comment.objects.all().delete()
👉 터미널을 사용하는 목적은 ORM 구문을 빠르게 시험해보고, 실제 DB 반영 전 동작을 확인하기 위한 실습 환경이라는 개념
⭐ 보충 개념 정리
- media 폴더 구조: 업로드된 파일은 media 폴더에 저장됨. 로컬에 있을 수도, 클라우드에 있을 수도 있는 구조
- 이미지 처리 방식: 이미지는 binary 데이터로 전달되고, Django가 URL 경로로 관리하는 구조
- ORM 자동 처리: Post.objects.create(...) 같은 메서드가 대부분 자동 처리해주어 ORM이 좋아보이기도 하지만, SQL문으로 직접 개발하는 경우도 있기 때문에 항상 좋은 건 아님
- 마이그레이션/버전관리 규칙: 모델 변경시 makemigrations → migrate 순서 준수하기!
- redirect 시 주의: redirect("/posts/")처럼 앞뒤로 /를 반드시 붙여야 하는 특징. 잘못 작성하면 URL 매칭 에러가 발생할 수 있음.
- 글 작성(post_add) 요청 처리 절차

'LG U+ Why Not SW Camp 8기 > 학습 로그' 카테고리의 다른 글
| 공부 일지 #45 | Django 실습4: 템플릿 적용과 1:N 관계 구현 (0) | 2025.10.05 |
|---|---|
| 공부 일지 #44 | Django 실습3: 로그인과 회원가입 (0) | 2025.10.04 |
| 공부 일지 #42 | Flask & Django 실습 (0) | 2025.09.28 |
| 공부 일지 #41 | Flask & 크롤링 첫걸음 (0) | 2025.09.21 |
| 공부 일지 #40 | HTML과 CSS 배우기 (1) | 2025.09.21 |