지난 글에 이어서 북마크 서비스 페이지를 만들어 봅니다.
이번에는 서비스의 각 기능들을 추가 해봅니다.
개인 공부를 하며 내용을 정리합니다.
Code: https://github.com/ghk0409/Django_bookmark/
9. 북마크 추가 기능 구현
- 북마크 추가를 위한 'BookmarkCreateView' 클래스 뷰를 만들어줍니다.
+ 제네릭 뷰인 CreateView를 상속받아 쉽게 만들어봅니다.
# bookmark/views.py
# 기존 views.py에 아래 코드 추가
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
# CreateView를 상속받아 사용
class BookmarkCreateView(CreateView):
# model : 어떤 모델을 입력 받을 것인가
# fields : 어떤 필드들을 입력 받을 것인가
# success_url : create 완료 후 이동할 페이지 url, 보통 상세 페이지로 이동하지만 여기서는 목록 페이지
# template_name_suffix : 사용할 템플릿의 접미사만 변경하는 설정값 / bookmark_create 템플릿 파일 사용
model = Bookmark
fields = ['site_name', 'url']
success_url = reverse_lazy('list')
template_name_suffix = '_create'
+ urls.py에서 기본 목록 페이지 URL 이름을 'list'로 설정했으니 success_url이 해당 URL 패턴을 찾아서 이동 시켜줍니다!!
- 뷰를 완성했으니 URL을 연결해줍니다.
※ 기억하기 : 뷰를 만듦 -> 뷰를 보여주기 위해 URL 연결 -> 해당 뷰를 어떻게 보여줄지 템플릿 만들기
# bookmark/urls.py
# BookmarkCreateView path 추가하기
from .views import BookmarkListView, BookmarkCreateView
urlpatterns = [
path('', BookmarkListView.as_view(), name='list'),
path('add/', BookmarkCreateView.as_view(), name='add'), # 이 부분을 추가해주기!!
]
- 이어서 BookmarkCreateView를 위한 템플릿도 만들어줍니다.
+ bookmark/templates/bookmark 폴더에 'bookmark_create.html' 파일을 만들어주기
# bookmark/templates/bookmark/bookmark_create.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post"> <!--action 메서드 비워두면 현재 페이지로 전달-->
{% csrf_token %} <!--CSRF 공격을 막기 위한 용도-->
{{form.as_p}} <!--클래스형 뷰의 옵션 값으로 설정한 필드를 출력할 때 P태그로 감싸줌-->
<input type="submit" value="Add" class="btn btn-info btn-sm">
</form>
</body>
</html>
** CSRF(Cross Site Request Forgery)를 막기 위한 'csrf_token'이란?
- CSRF: 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격방법을 의미
[관련 내용을 잘 정리해두신 블로그 참고 : https://sj602.github.io/2018/07/14/what-is-CSRF/]
- 해커가 만든 외부 사이트에서 내가 만든 사이트에 로그인 한 사용자 권한으로 공격하는 것을 막기 위한 용도
- 서버 실행 후 추가 기능을 테스트 해봅니다.
+ http://127.0.0.1:8000/bookmark/add/ 주소로 접속해서 추가 기능 페이지를 먼저 테스트 해봅니다.
+ [Add] 버튼을 누르면 DB에 해당 내용이 저장되고 목록 화면으로 돌아옵니다.

- 목록 페이지 위쪽의 [Add Bookmark] 버튼이 잘 작동하도록 해당 버튼에 링크를 추가해줍니다.
+ 아래와 같이 수정 후, 서버 실행한 뒤(이미 실행 중이면 해당 페이지 새로고침!!) [Add Bookmark] 버튼 누르면 추가 기능 페이지로 잘 이동 성공~
+ <div> 태그의 Add Bookmark 버튼 href를 수정합니다.
# bookmark/templates/bookmark/bookmark_list.html
<!--[Add Bookmark] 링크가 동작하도록 href 속성 값 변경-->
<!--[add] 이름을 가진 URL 패턴을 찾아서 URL 출력 (url = 템플릿 태그)-->
<a href="{% url 'add' %}" class="btn btn-info">Add Bookmark</a>
10. 북마크 확인 기능 구현
- 북마크의 확인 기능으로 상세 페이지를 구현해봅니다.
+ BookmarkDetailView 클래스 뷰 만들기
+ DetailView를 상속받아 쉽게 쉽게 갑니다
# bookmark/views.py
# 기존 views.py에 아래 코드 추가
from django.views.generic.detail import DetailView
class BookmarkDetailView(DetailView):
model = Bookmark
- 뷰를 만든 후, URL을 연결합니다.
# bookmark/urls.py
# 클래스 3개 다 쓰면 길어지니까 그냥 '*'로 모두 import 시키기
from .views import *
# urlpatterns에 path 추가!!
urlpatterns = [
path('', BookmarkListView.as_view(), name='list'),
path('add/', BookmarkCreateView.as_view(), name='add'),
path('detail/<int:pk>/', BookmarkDetailView.as_view(), name='detail'),
# [<int:pk>] : int 타입의 변수명
# 앞쪽(int)을 '컨버터'라고 부름(클래스 형태) -> 생략하거나 커스텀 컨버터 가능
# 뒤쪽(pk)은 컨버터를 통해 반환받은 값 / 패턴에 일치하는 값의 변수명
]
※ 컨버터의 종류 살펴보기
** 기본 제공 컨버터 종류
1) str : 비어있지 않은 모든 문자와 매칭 (단, '/'는 제외!!) 컨버터를 설정하지 않을 경우의 기본 컨버터
2) int : 0을 포함한 양의 정수와 매칭
3) slug : 아스키 문자나 숫자, 하이픈, 언더스코어를 포함한 슬러그 문자열과 매칭
4) uuid : UUID와 매칭, 같은 페이지에 여러 URL이 연결되는 것을 막으려고 사용
5) path : 기본적으로 str과 같은 기능이나 '/'도 포함!!, URL의 부분이 아닌 전체에 대한 매칭을 하고 싶을 때 사용
- 상세 페이지를 위한 템플릿도 만들어줍니다. (bookmark_detail.html 만들기)
# bookmark/templates/bookmark/bookmark_detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--북마크 하나의 정보만 출력-->
<!--DetailView가 object라는 이름으로 북마크 값을 전달함-->
<!--object변수를 이용해 값을 하나씩 출력-->
{{object.site_name}}<br/>
{{object.url}}
</body>
</html>
- 목록 페이지에서 사이트 이름을 클릭 시, 상세 페이지로 이동할 수 있도록 링크를 추가해줍니다.
+ <tr> 태그에서 bookmark.site_name 부분의 href를 수정합니다.
+ 수정 후, 목록 페이지에서 사이트 이름 클릭하면 상세 페이지로 이동 성공!!
# bookmark/templates/bookmark/bookmark_list.html
<!--각 리스트의 DetailView 링크 연결하기-->
<!--pk값에 bookmark의 id값을 담아서 detail 페이지로 전달-->
<td><a href="{% url 'detail' pk=bookmark.id %}">{{bookmark.site_name}}</a></td>
11. 북마크 수정 기능 구현
- 수정 기능은 추가 기능과 거의 동일하며 UpdateView를 상속받아 만들어줍니다.
+ BookmarkUpdateView 클래스 만들기
# boomark/views.py
# generic edit 뷰 중 하나인 UpdateView Import!!
from django.views.generic.edit import CreateView, UpdateView
# UpdateView 상속받아 사용
class BookmarkUpdateView(UpdateView):
model = Bookmark
fields = ['site_name', 'url']
template_name_suffix = '_update'
# 접미사 _update => bookmark_update.html이 템플릿이 된다는 이야기!!
- 뷰를 만들고 URL을 연결해줍니다.
# bookmark/urls.py
# urlpatterns에 추가하기
path('update/<int:pk>/', BookmarkUpdateView.as_view(), name='update'),
- 뷰를 표시해줄 템플릿을 만들어줍니다.
+ bookmark_update.html 파일 생성하기
# bookmark/templates/bookmark/bookmark_update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Update" class="btn btn-info btn-sm">
</form>
</body>
</html>
- 수정 기능도 링크로 연결해줍니다.
+ bookmark_list.html의 [Modify] 버튼 href를 수정해봅니다.
# bookmark/templates/bookmark/bookmark_list.html
<!--Modify 부분 수정-->
<td><a href="{% url 'update' pk=bookmark.id %}" class="btn btn-success btn-sm">Modify</a></td>
- 여기까지 진행하고 [Modify] 버튼을 눌러 Update를 마치면 오류가 발생합니다. 수정 완료 후 이동할 페이지 설정을 하지 않았기 때문이에요.
+ DB에는 해당 수정된 값이 잘 저장되긴 했을 겁니다!!
- 수정 완료 후, 이동할 페이지는 뷰에 success_url이 설정되어 있거나 Model에 'get_absolute_url'이라는 메서드를 통해 결정합니다.
+ 지금은 두 가지 모두 없어서 오류가 발생합니다.
+ 북마크 추가 기능에서 success_url 설정은 해봤으니 이번에는 get_absolute_url을 진행해봅니다!!
+ models.py에서 해당 메서드를 추가해봅니다.
# bookmark/models.py
from django.urls import reverse
class Bookmark(models.Model):
# ... 중략
# Bookmark 클래스에 get_absolute_url 메서드 추가!!
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# get_absolute_url 메서드는 장고에서 사용하는 메서드
# 보통 객체의 상세 화면 주소(detail)를 반환하게 만듦
# reverse 메서드는 URL 패턴의 이름과 추가 인자를 전달받아 URL을 생성하는 메서드!!
+ 위처럼 get_absolute_url 메서드를 추가하고 수정 기능을 다시 테스트하면 수정 후 상세 페이지로 이동이 됩니다!!
12. 북마크 삭제 기능 구현
- 마지막으로 삭제 기능을 구현해봅니다.
+ 지금까지 진행한 과정과 동일하게 기능을 만들기 때문에 클래스 뷰 생성, 뷰 URL 연결, 목록 페이지의 삭제 기능 링크 연결까지 쭉 진행해봅니다.
+ 원래 뷰 URL 연결하고 나면 해당 뷰의 템플릿을 만들 차례인데??라고 의문이 든다면 이제 Django View 만드는데 익숙해진 것이지만 이번에는 잠깐 예외 사항이 있어서 잠시 미뤄두겠습니다ㅎㅎ
# bookmark/views.py
# BookmarkDeleteView 클래스 추가하기
from django.views.generic.edit import CreateView, UpdateView, DeleteView
class BookmarkDeleteView(DeleteView):
model = Bookmark
success_url = reverse_lazy('list')
# 삭제 후 목록 페이지로 이동
# bookmark/urls.py
# urlpatterns에 path 추가
path('delete/<int:pk>/', BookmarkDeleteView.as_view(), name='delete'),
# bookmark/templates/bookmark/bookmark_list.html
<!--delete 페이지 href 연결하기-->
<td><a href="{% url 'delete' pk=bookmark.id %}" class="btn btn-danger btn-sm">Delete</a></td>
- 여기까지 진행한 뒤, [Delete] 버튼을 테스트해보면 아래와 같은 페이지를 볼 수 있습니다.

+ 지금까지 사용했던 템플릿 이름은 모델명_xxx.html 형태(ex. bookmark_list.html)였는데 오류 메시지에는 '_confirm'이 추가된 것을 볼 수 있습니다.
+ 이 부분을 참고해서 'bookmark_confirm_delete.html' 파일을 만들어줍니다!!
+ 삭제할 때는 확인이 필요하기 때문에 confirm_delete라는 이름을 사용합니다.
# bookmark/templates/bookmark/bookmark_confirm_delete.html
<!--삭제할 때는 확인이 필요해서 confirm_delete라는 이름을 사용-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--form 태그와 csrf_token은 혼연일체라고 생각!!-->
<form action="" method="post">
{% csrf_token %}
<div class="alert alert-danger">Do you want to delete Bookmark "{{object}}"?</div>
<input type="submit" value="Delete" class="btn btn-danger">
</form>
</body>
</html>
+ 이후 다시 [Delete] 버튼을 누르면 해당 삭제 기능이 잘 작동되는 것을 볼 수 있습니다.
여기까지 북마크 서비스에서 사용할 기능은 모두 구현했습니다.
뷰 생성 -> 뷰 URL 연결 -> 뷰 템플릿 생성 -> 링크 연결의 작업을 반복하면서 Django에서의 기본적인 View가 만들어지는 과정에 익숙해졌을 겁니다.
이렇게 반 복 학 습 을 하면서 공부해 나가봅니다!!
그럼 다음 페이지에서는 웹 서비스를 더 이쁘게 보여줄 수 있도록 디자인을 적용해봅니다!!
해당 프로젝트는 "베프의 오지랖 파이썬 웹 프로그래밍(디지털북스)"를 참고합니다.
'Django > Project' 카테고리의 다른 글
[Project] Ongstagram Service #1 (0) | 2021.06.01 |
---|---|
[Project] Ong's BookMark Service #5 (1) | 2021.05.29 |
[Project] Ong's BookMark Service #3 (0) | 2021.05.29 |
[Project] Ong's BookMark Service #2 (0) | 2021.05.27 |
[Project] Ong's BookMark Service #1 (0) | 2021.05.25 |