일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- BOJ #컴퓨터공학 #C++ #알고리즘 #자료구조
- 컴퓨터공학 #자료구조 #스택 #c++ #알고리즘 #백준문제풀이
- 컴퓨터공학 #c #c언어 #문자열입력
- HTML #CSS
- 컴퓨터공학 #Java #자바 #클래스 #객체 #인스턴스
- 잔
- Today
- Total
영벨롭 개발 일지
[Django]글 작성 & 사진 첨부 & 댓글 작성 가능한 모델 만들기 - 정리 본문
[ 기본 세팅 ]
1. 가상환경 생성 및 활성화
$ python -m venv myvenv
$ source myvenv/Scripts/activate
2. django 설치, 프로젝트 생성 및 이동
$ pip install django
$ django-admin startproject myproj
$ cd myproj
3. Application 생성 및 settings.py에서 application 등록
$ python manage.py startapp myapp
# myproj/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp' # 어플리케이션 등록
]
[ 기본 페이지 작성 및 URL 등록 ]
1. myapp/templates 폴더 생성 후, index.html 생성
2. index.html 작성
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Django로 글 작성하기</h1>
</body>
</html>
3. urls.py & views.py 작성
# myapp/views.py
from django.shortcuts import redirect, render
def home(request):
return render(request, 'index.html')
# myproj/urls.py
from django.contrib import admin
from django.urls import path
from myapp import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home, name='home')
]
[ static & media 세팅 ]
1. myproj/ 하위에 static, media 폴더 생성
2. settings.py 수정
# settings.py
import os
...
STATIC_URL = 'static/'
STATICFILES_DIRS = [
BASE_DIR / 'static'
]
# 사용자가 업로드한 미디어 파일이 저장되는 루트 경로
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 사용자에 의해 업로드 된 미디어 파일을 접근할 경로
MEDIA_URL = 'media/'
...
[ 모델 & 폼 만들기 ]
1. Post, Comment 모델 만들기
# myapp/models.py
from distutils.command.upload import upload
from django.db import models # django의 models improt!!
class Post(models.Model):
# 데이터마다 타입 명시
title = models.CharField(max_length=50) # post의 제목
body = models.TextField()
# 첨부한 사진 media/post_photo에 업로드
photo = models.ImageField(blank=True, null=True, upload_to='post_photo')
# auto_now_add=True: 자동으로 현재 시간을 추가
date = models.DateTimeField(auto_now_add=True)
# admin 사이트에서 Post 객체를 title로 표시
def __str__(self):
return self.title
class Comment(models.Model):
comment = models.TextField()
date = models.DateTimeField(auto_now_add=True)
# Comment 객체는 Post 객체를 참조하기 때문에 외래키 설정
# on_delete=models.CASCASE : 참조중인 Post 객체가 삭제된다면 해당 댓글도 삭제
post = models.ForeignKey(Post, on_delete=models.CASCADE)
def __str__(self):
return self.comment
2. PostForm, CommentForm 모델폼 만들기
# myapp/forms.py
from dataclasses import field
from django import forms
from .models import Post, Comment
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'photo', 'body']
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['comment']
3. admin 사이트에 모델 등록
# myapp/admin.py
from django.contrib import admin
from .models import Post, Comment
admin.site.register(Post)
admin.site.register(Comment)
4. migration
$ python manage.py makemigrations
$ python manage.py migrate
[ 새 글 작성 페이지 ]
1. views.py 에서 로직 작성
# myapp/views.py
from .models import Post
from .forms import PostForm
# 새 글 작성 폼
def post_form(request):
# POST 요청이라면 -> 작성한 폼을 가져와서 DB에 저장하고 'home' 페이지로 이동
if request.method == 'POST' or request.method == 'FILES':
form = PostForm(request.POST, request.FILES)
if form.is_valid(): # 유효성 검사
form.save() # DB에 저장
return redirect('home')
# GET 요청이라면 -> 폼을 보여줘야 함
else:
form = PostForm()
return render(request, 'post_form.html', {'form': form})
2. 폼 페이지
<!-- myapp/templates/post_form.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>새 글 작성 페이지</title>
</head>
<body>
<!-- action=데이터를 처리할 서버 url, 빈문자열이면 현재 페이지로
method='POST' POST 요청 보내야함
enctype: 폼 데이터가 서버로 제출될 때 해당 데이터가 인코딩되는 방법 명시
: method가 'POST'인 경우에만 사용 가능
multipart/from-data: 모든 문자를 인코딩하지 않음을 명시, 파일이나 이미지 제출할때 사용-->
<form action="" method="POST" enctype="multipart/form-data">
<!-- django에서 form 태그를 사용하기 위해선 token 사용 필수 -->
{% csrf_token %}
<!-- django의 폼은 table로써 표현 가능 -->
<table>
{{ form.as_table }}
</table>
<!-- 서버로 데이터 전송 -->
<input type="submit" value="새 글 작성">
</form>
</body>
</html>
3. urls.py 에 폼 페이지 추가
# myproj/urls.py
from django.contrib import admin
from django.urls import path
from myapp import views
from django.conf import settings # media
from django.conf.urls.static import static # media
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home, name='home'),
path('postform/', views.post_form, name='post_form'),
]
# media 파일을 접근할 수 있는 url도 추가해야 함 (외우는 것이 좋음)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
4. index.html 에서 새 글 작성 페이지로 가는 <a> 태그 추가
<!-- myapp/templates/index.html -->
<body>
<h1>Django로 글 작성하기</h1>
<!-- '새 글 작성' 을 누르면 urls.py에 등록한 post_form 이름의 path() 실행 -->
<div class="new-post">
<a href="{% url 'post_form' %}">새 글 작성</a>
</div>
</body>
[ 작성된 글 목록 띄우기 ]
1. views.py 에서 작성된 모든 Post 객체 넘겨주기
# myapp/views.py
def home(request):
# 작성한 글들을 index.html에 띄우기
# Post 객체를 DB에서 모조리 가져오기, 'date' 내림차순으로
posts = Post.objects.filter().order_by('-date')
return render(request, 'index.html', {'posts': posts})
2. index.html에서 넘겨받은 Post 객체를 for 문을 통해 띄우기
<!-- index.html -->
<body>
<h1>Django로 글 작성하기</h1>
<!-- '새 글 작성' 을 누르면 urls.py에 등록한 post_form 이름의 path() 실행 -->
<div class="new-post">
<a href="{% url 'post_form' %}">새 글 작성</a>
</div>
<hr/>
<!-- 게시글 띄우기 -->
{% for post in posts %}
<ul class="post-list">
<li>
<a href="#">{{ post.title }}</a>
<span>{{ post.date }} (post.id: {{ post.id }})</span>
</li>
</ul>
{% endfor %}
</body>
[ 각 게시글의 디테일 페이지 & 댓글 기능 ]
1. index.html 수정 -> 해당 게시글의 제목을 누르면 각 게시글의 디테일 페이지로 이동할 수 있는 url 설정
<!-- index.html -->
...
<!-- 게시글 띄우기 -->
{% for post in posts %}
<ul class="post-list">
<li>
<!-- name='detail' 인 url로 요청을 보내는데, 이때 각 게시글을 구분하기 위해
post.id 도 같이 넘겨주어야 함-->
<a href="{% url 'detail' post.id %}">{{ post.title }}</a>
<span>{{ post.date }} (post.id: {{ post.id }})</span>
</li>
</ul>
{% endfor %}
2. urls.py 에 URL 등록
# myproj/urls.py
from django.contrib import admin
from django.urls import path
from myapp import views
from django.conf import settings # media
from django.conf.urls.static import static # media
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home, name='home'),
path('postform/', views.post_form, name='post_form'),
# 만약 post.id 가 1이라면 127.0.0.1:8000/detail/1 url에선
# post.id가 1인 게시글을 보여주어야 함
# 이때 views.py의 detail() 함수의 첫번째 인수는 request, 두번째 인수는 post_id
path('detail/<int:post_id>', views.detail, name='detail'),
# 댓글 객체를 보여줄 함수
path('comment/<int:post_id>', views.comment, name='comment'),
]
# media 파일을 접근할 수 있는 url도 추가해야 함 (외우는 것이 좋음)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
3. views.py 에서 detail() 함수 정의 -> 디테일 페이지를 렌더링해주는 함수
# myapp/views.py
def detail(request, post_id):
# 이때 request는 GET 요청!
# get_object_or_404 메소드를 통해 DB에서 Post 객체 중,
# 기본키 pk가 post_id 인 객체를 찾고 찾지 못하면 404를 반환
post_detail = get_object_or_404(Post, pk=post_id)
# 각 게시글의 댓글 폼 보여주어야 함
comment_form = CommentForm()
return render(request, 'detail.html',
{'post_detail': post_detail, 'comment_form': comment_form})
4. detail.html 작성
<!-- detail.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Detail 페이지</title>
</head>
<body>
<h1>제목: {{ post_detail.title }}</h1>
<h3>작성날짜: {{ post_detail.date }}</h3>
<h4>본문</h4>
<p>
{{ post_detail.body }}
</p>
<!-- 사진이 첨부되어 있다면 사진 보여주기 -->
{% if post_detail.photo %}
<img src="{{ post_detail.photo.url }}" alt="본문사진" height="200">
{% endif %}
<!-- 댓글 폼 -->
<!-- 제출 버튼을 누르면 댓글 폼을 Post 해줄 서버로 넘겨주어야 함-->
<!-- 이때 Comment 객체는 Post 객체를 외래키로 가지고 있기 때문에
post_detail의 id도 넘겨주기 -->
<form action="{% url 'comment' post_detail.id %}" method="POST">
{% csrf_token %}
{{ comment_form }}
<input type="submit" value="댓글 작성">
</form>
</body>
</html>
5. views.py 에서 각 게시글의 댓글 목록을 보여줄 함수 작성
# myapp/views.py
def comment(request, post_id):
# CommentForm 객체 가져오기
form = CommentForm(request.POST)
if form.is_valid():
# 일단은 DB에 저장하지 않고 대기하기
finished_form = form.save(commit=False)
# post_id에 상응하는 Post 객체를 찾고 Comment 객체의 post에 저장해야함
# post는 Comment 객체의 외래키!
finished_form.post = get_object_or_404(Post, pk=post_id)
# DB에 반영
finished_form.save()
return redirect('detail', post_id)
6. detail.html 에서 댓글들의 목록 보여주기
<!-- detail.html -->
...
<hr>
<!-- 댓글 목록들 -->
<!-- django에서는 특정 객체의 집합들을 객체_set 이라고 함-->
{% for comment in post_detail.comment_set.all %}
<div class="comment">
<span>{{ comment }}</span>
<span>{{ comment.date }}</span>
</div>
{% endfor %}
'Back-end > Django' 카테고리의 다른 글
[Django]장고에서 사용자 입력받기 - Form 이용하기 (0) | 2022.05.18 |
---|---|
[Django]장고 Model 만들기 - ORM & Migration (0) | 2022.05.17 |
[Django]장고를 위한 최소한의 데이터베이스 DB (0) | 2022.05.17 |
[Django]장고 static 파일 다루기 (0) | 2022.05.12 |
[Django] 장고 URL 등록하기: path(), include() (0) | 2022.05.12 |