본문 바로가기

Django/Project

[Project] Ong's BookMark Service #4


지난 글에 이어서 북마크 서비스 페이지를 만들어 봅니다.

이번에는 서비스의 각 기능들을 추가 해봅니다.

개인 공부를 하며 내용을 정리합니다.

 

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] 버튼 누른 후 돌아온 목록 페이지 화면(깃허브 추가 성공!!)

 

- 목록 페이지 위쪽의 [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' 카테고리의 다른 글