블로그를 만드는 마지막 파트다. 사용자가 관리자모드에서가 아닌 직접 블로그 창에서 글과 댓글을 작성하는 기능을 구현해본다.
일단 늘 페이지를 만들 때 하던 '글 작성 페이지'의 기본 구조 만들자. 순서는 View -> URLconf -> Template !! (순서 상관은 크게 없음)
[blog/views.py]
def post_add(request):
return render(request, 'post_add.html')
[config/urls.py]
from blog.views import post_add # 위에서 만든 veiws.py에 post_add 함수 추가
...
urlpatterns = [
...
path("posts/add/", post_add),
]
[templates/post_add.html]
{% load static %}
<!doctype html>
<html lang='en'>
<head>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<div>
<h1>Post Add</h1>
</div>
</body>
</html>
1. 사용자의 입력을 받는 Template
사용자의 입력을 받을 .../posts/add/ 페이지에 기본 구성을 만들어보자. 기본 구성을 만듬과 동시에 데이터도 전송해보자
1-1. HTML 형태 구현
[templates/post_add.html]
...
<body>
<div>
<h1>Post Add</h1>
<form method="GET">
<div>
<label>제목</label>
<input name='title' type='text'>
</div>
<div>
<label>내용</label>
<textarea name='cotent' cols='50' rows='10'></textarea>
</div>
<button type='submit'>작성</button>
</form>
</div>
</body>
input과 textarea에 각각 name='title', name='content'를ㄹ 추가하여 각각의 요소에 입력된 값이 어떤 이름으로 View에 전달될지 지정한다. <button>에 type='submit' 속성을 추가하여 이 버튼을 클릭 시 <form>의 데이터를 전송하도록 지정한다.
이렇게 실행을 해보면 URL로 값을 전달하여 검색을 수행할 수 있다. 하지만 우리가 하고자 하는 것은 단순한 조회가 아닌 DB에 새로운 객체를 생성하려고 하는 것이다. 이 과정을 URL을 통해 하는 것은 여러 가지 제약이 있으며 보안상으로도 좋지 않다. 이를 GET 메서드를 사용한 전송이라고 부르면 반면, URL을 통하지 않고 더 많은 데이터를 제약 없이 보내려면 POST 메서드를 사용해야 한다. POST 메서드를 사용하려면 위에서 이미 method="GET"으로 정의된 값을 "POST"로 바꾸면 된다. 이때 단순히 POST로 바꾸고 실행하면 Forbidden 오류가 뜬다. Forbidden 오류가 뜨는 이유는 GET보다 POST가 더 높은 보안 수준을 적용하기 때문인데 Django의 CSRF 공격 방어기법이 적용되기 때문이다. 설명에는 브라우저별로 구분되는 값으로 치환을 해줘야 한다고 나와있다. 정확하게 이해는 못해서 일단 그냥 넘어간다.
1-2. Forbidden 오류를 수정한 form
{% csrf_token %} 태그를 추가해주면 오류가 나지 않는다.
[templates/post_add.html]
<h1>Post Add</h1>
<form method="POST">
{% csrf_token %}
<div>
2. View에서 POST 요청 처리
2-1. POST데이터 다루기와 메서드에 따른 분기 처리
이제 요청에 전달된 데이터를 다루어보자
[blog/views.py]
def post_add(request):
if request.method == "POST": # method가 POST일 때
title = request.POST['title']
content = request.POST["content"]
return render(request, "post_add.html")
기본은 method가 GET일 때 실행이 되기 때문에 POST로 불러올 때는 이렇게 지정을 해줘야 한다. 그리고 template에서 지정해줬던 name의 변수를 title과 content에 변수 할당을 해준다.
2-2. POST 데이터를 사용한 DB row 생성
가져온 데이터를 사용해 DB에 새 row를 생성해야한다. 이때 objects.create 메서드를 사용하면 된다. shell에서 먼저 연습해보자
>>> from blog.models import Post
# Admin에서 생성한 글 목록이 출력된다.
>>> Post.objects.all()
# 새 객체를 만든다.
>>> post = Post.objects.create(title="ShellTtile", content="ShellContent")
# 모든 Post를 생성 순서의 역순으로 가져온다.
>>> Post.objects.order_by('-id')
이렇게 인터프리터에서 만들어도 관리자 페이지에서 확인할 수 있다.
이제 view에서 객체를 생성해보자.
[blog/views.py]
def post_add(request):
if request.method == "POST":
title = request.POST['title']
content = request.POST['content']
Post.objects.create(
title=title,
content=content,
)
return render(request, "post_add.html")
2-3. 글 작성 완료 후 이동하기
지금까지 사용했던 render 함수는 인수로 전달된 html 파일을 브라우저로 보여주는 역할을 한다. 우리가 이번에 추가해야 할 기능은 글을 작성했을 때 작성한 글의 상세페이지로 이동해야 한다. 이때 사용되는 함수는 redirect 이다.
[blog/views.py]
from django.shortcuts import redirect # shortcuts 패키지 안에 redirect 함수를 사용한다.
def post_add(request):
if request.method == 'POST':
title = request.POST['title']
content = request.POST['content']
thumbnail = request.FILES['thumbnail']
post = Post.objects.create(
title=title,
content=content,
thumbnail=thumbnail,
)
return redirect(f"/posts/{post.id}/") # 글 작성을 완료하고 해당 글의 상세페이지로 이동한다.
return render(request, "post_add.html")
3. CSS 적용 및 링크 생성
이제 template에 css까지 적용해보자.
[templates/post_add.html]
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href = "{% static 'css/style.css' %}">
</head>
<body>
<div id="navbar"> # 상단에 id='navabr' css 적용
<span>글 작성</span>
</div>
<div id="post-add"> # 기존에 있던 form 형태에 id='post-add'을 적용
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div>
<label>제목</label>
<input name='title' type="text">
</div>
<div>
<label>내용</label>
<textarea name="content" cols="50" rows="10"></textarea>
</div>
<button type="submit" class="btn btn-primary">작성</button> # 작성 버튼에 'btn btn-primary' 적용
</form>
</div>
</body>
</html>
그리고 기존에는 posts/add/를 url창에 직접 쳐서 들어왔다면 이제 posts/ 창에서 바로 들어올 수 있게 링크를 연결해 주자.
[templates/post_list]
...
<body>
<div id="navbar">
<span>Woojin's blog</span>
<a href="/posts/add/" class="btn btn-primary">글 작성</a>
</div>
...
확인을 해보면 우측 상단에 글작성 링크가 들어가있는 것을 볼 수 있다. (posts/add/ 에 있는 작성 class와 같은 class를 썼기 때문에 같은 css가 적용되었다.)
4. 댓글 작성
이제 페이지에서 직접 댓글을 달 수 있는 기능을 만들어보자. 우선 ORM 에서 먼저 확인을 해보자
>>> from blog.models import Comment
# 이전에 생성했던 댓글들을 전부 지워준다.
>>> Comment.objects.all().delete()
# 글을 작성했을 때와 같이 content 속성을 사용해 댓글을 만들어보
>>> Comment.objects.create(content='SampleContent')
위와 같이 시도해보면 django.db.utils.IntegrityError 오류가 발생한다. 왜냐하면 Comment 모델은 Post 모델과 ForeignKey 관계로 연결되어 있기 때문이다.
>>> from blog.models import Post
# 가장 처음으로 생성된 post를 가져온다
>>> post = Post.objects.first()
# 가장 처음으로 생성된 post와 연결되는 comment를 생성한다.
>>> Comment.objects.create(post=post, content ='SampleComment')
이렇게 Comment를 생성하려면 어떤 Post와 연결될지를 반드시 지정해주어야 한다.
이제 댓글을 브라우저에서 바로 달 수 있게 창을 만들어줘야한다. 각각의 상세페이지안에 만들어야 하므로 post_detail html을 만져준다.
[templates/post_detail.html]
...
<form method='POST'>
{% csrf_token %}
<textarea name='comment'></textarea>
<button type='submit' class='btn btn-primary'>댓글 작성</button>
</form>
...
이제 view에서 comment를 생성할 차례이다.
[blog/views.py]
...
def post_detail(request, post_id):
post = Post.objects.get(id=post_id)
if request.method == 'POST':
comment_content = request.POST['comment']
Comment.objects.create(
post=post,
content=comment_content,
)
context = {
"post":post,
}
return render(request, 'post_detail.html', context)
5. 글 작성 시 이미지 업로드
Post 모델에는 썸네일을 다루는 이미지 필드가 있다. 텍스트와 다르게 이미지와 같은 파일을 form 으로 전달받으려면 Template과 View에서 별도의 처리가 필요하다.
[templates/post_add.html]
...
<div id = 'post_add'>
<form method='POST' enctype="multipart/form-data"> # 데이터를 서버로 전송할 때 어떤 인코딩 유형을 사용할 것인지
...
<div>
<label>썸네일</label>
<input name='thumbnail' type='file'>
</div>
<button type="submit" class="btn btn-primary">작성</button>
</form>
전송된 파일은 veiws에 request.POST가 아닌 request.FILES에서 가져와야 한다.
[blog/views.py]
def post_add(request):
if request.method == 'POST': # method가 POST일 때
title = request.POST['title']
content = request.POST['content']
thumbnail = request.FILES['thumbnail']
post = Post.objects.create(
title=title,
content=content,
thumbnail=thumbnail,
)
return redirect(f"/posts/{post.id}/")
return render(request, "post_add.html")
여기까지 글과 댓글을 직접 브라우저에서 만들 수 있는 기능을 만들어보았다. 잘 실행되는지도 확인해보자!!
댓글까지 잘 달리는 것을 확인할 수 있었다. 직접 나만의 블로그를 만드니 뿌듯하다 ㅎㅎ 나중에 좀 더 수정해서 괜찮은 블로그도 만들어봐야겠다
'Python > Django' 카테고리의 다른 글
[Django] woojin's blog 프로젝트: 글 상세 페이지 (1) | 2023.06.16 |
---|---|
[Django] woojin's blog 프로젝트: 유저가 업로드하는 정적파일 (0) | 2023.06.16 |
[Django] woojin's blog 프로젝트: CSS와 정적파일 (0) | 2023.06.15 |
[Django] woojin's blog 프로젝트: 글과 댓글 보여주기 (0) | 2023.06.15 |
[Django] woojin's blog 프로젝트: 글과 댓글 모델 구현 (1) | 2023.06.14 |