Programming/Django

클래스형 뷰를 사용한 CRUD(1)-CRUD 구현

코딩하는 포메라니안 2021. 6. 23. 23:13

0. 클래스형 뷰란?

Django의 views.py에서 함수형(def), 클래스형(class)를 모두 제공하고 있다.

클래스형 뷰의 장점은 아래와 같다.

  • 이미 구현되어 있는 기능을 상속으로 받아와서 쓸 수 있다.
  • 코드가 길어지거나 개발하는 웹 or 앱의 규모가 큰 경우 코드를 깔끔하게 볼 수 있다.

이때, Django에 이미 구현해서 제공하는 기능들을 제네릭 뷰라고 한다.

 

1. 프로젝트 시작하기

 

Project 시작하기

1) 가상환경 켜기 $ python -m venv myvenv $ source myvenv/Scripts/activate 2) 가상환경에 django 설치 $ pip install django 3) project 만들기 $ django-admin startproject staticproject 4) app 만들기 cd..

yerinpy73.tistory.com

 

2. 모델만들기

데이터를 어떤 틀에 담아서 저장해놓고 쓸지 정의합니다.

저는 사이트의 이름과 그 사이트의 url 이 두 가지 정보를 담을 클래스를 정의하였습니다.

#app/models.py
from django.db import models

class Bookmark(models.Model):
    site_name = models.CharField(max_length=100)
    url = models.URLField('Site URL')

    #객체의 이름은 아래와 같이 지어주겠다.
    def __str__(self):
        return "이름 : "+self.site_name+",주소 : "+self.url
$ python manage.py makemigrations
$ python manage.py migrate

관리자 페이지에서 볼 수 있도록 클래스를 등록해줍니다.

#app/admin.py
from django.contrib import admin
from .models import Bookmark

admin.site.register(Bookmark)
$ python manage.py createsuperuser

실행시켜서, 객체 하나를 만들어 주겠습니다. 게시판에 글 하나를 작성하시는 것과 같습니다.

$ python manage.py runserver

먼저, 주소창에 '/admin'을 붙여서 접속합니다.

createsuperuser로 만들었던 계정으로 로그인하면, 아래와 같은 화면을 볼 수 있습니다.

Bookmarks 옆의 [+Add]를 눌러서 아무 사이트 이름과 URL을 입력한 후 [SAVE]를 클릭합니다.

 

3. [클래스형 뷰] 화면 구성하기

Django에서 제공하는 ListView클래스를 상속받아 사용해보겠습니다.

#app/views.py
from django.views.generic.list import ListView
from .models import Bookmark

class BookmarkListView(ListView):
    model = Bookmark

app폴더 내에 urls.py파일을 하나 생성하고, project의 urls.py와 이어주겠습니다.

#project/urls.py
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('bookmark/', include('classapp.urls')),
]
#app/urls.py
from django.urls import path
from .views import BookmarkListView

urlpatterns = [
    path('', BookmarkListView.as_view(), name='list'),
]

이제, templates 즉 html을 만들어 주겠습니다. classproject에 templates폴더를 생성해주고, 만든 폴더 안에 base.html파일을 하나 생성합니다.

<!--project/templates/base.html-->
<!DOCTYPE html>
<html lang="en">
<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>{% block title %}{% endblock %}</title>
</head>
<body>
    <div class="container">
        {% block content%}

        {% endblock%}
    </div>
</body>
</html>

https://getbootstrap.com/ 를 써서 보기 좋게 구성하려고 합니다. [Get started]를 눌러서 css와 js와 관련된 link를 연결해주겠습니다.

<!--project/templates/base.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    ...
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> 
</head>

settings.py에서 templates의 기본 주소를 project내의 templates폴더로 변경되었음을 알려줍니다.

#settings.py
import os
TEMPLATES = [
    {
        #...
        'DIRS': [os.path.join(BASE_DIR, "templates")],
        #...
]

그 다음, app안에 templates폴더를 생성하고, 그 안에 classapp이름의 폴더를 생성해서 또 그 안에 bookmark_list.html 파일을 생성합니다.

https://getbootstrap.com/ 에서 table을 검색해서 코드 복붙하고 수정하였습니다.

<!--bookmark_list.html-->
{% extends 'base.html' %}

{% block title %}Bookmark List{% endblock %}

{% block content %}
<table class="table">
    <thead>
        <tr>
            <th scope="col">#</th>
            <th scope="col">Site</th>
            <th scope="col">URL</th>
            <th scope="col">Modify</th>
            <th scope="col">Delete</th>
        </tr>
    </thead>
    <tbody>
        {% for bookmark in object_list %}
        <tr>
            <td>{{forloop.counter}}</th>
            <td>{{bookmark.site_name}}</td>
            <td><a href="{{bookmark.url}}" target="_blank">{{bookmark.url}}</a></td>
            <!-- target blank는 url을 눌렀을 때, 새창을 띄우겠다는 속성 -->
            <td><a href="#" class="btn btn-success btn-sm">Modify</a></td>
            <td><a href="#" class="btn btn-danger btn-sm">Delete</a></td>
        </tr>
        {%endfor%}

    </tbody>
</table>
{% endblock%}

4. [클래스형 뷰] Create 구현

장고에서 제공하는 CreateView를 상속받아서 썼다.

#views.py
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy

class BookmarkCreateView(CreateView):
    model = Bookmark #데이터 틀은 Bookmark를 쓰겠다.
    fields = ['site_name', 'url'] #이 두가지를 입력으로 받겠다. model에 정의한 이름으로
    success_url = reverse_lazy('list') #성공하면 list화면을 띄우겠다. => url에 정의됨
    template_name_suffix = '_create'
    #사용할 template이름은 '모델명'+'_create'

app/templates/classapp 안에 bookmark_create.html파일을 생성하고 url로 연결해준다.

from .views import BookmarkCreateView

urlpatterns = [
    #...
    path('add/', BookmarkCreateView.as_view(), name='add'),
]

아래는 bookmark_create.html 파일 코드이다.

<!--bookmark_create.html-->
{% extends 'base.html' %}

{% block title %}Bookmark Add{% endblock %}

{% block content %}
<form action="" method="post">
    {% csrf_token %}
    {{form.as_p}}
    <!-- form.as_p :클래스형 뷰의 옵션값임, 모델의 필드(site_name, URL)를 p태그로 감싸서 보여줌-->
    <input type="submit" value="Add" class="btn btn-info btn-sm">
</form>
{% endblock%}

bookmark_list화면에서 [Add]버튼을 누르면 bookmark_create화면으로 넘어가도록 하자.

<!--bookmark_list.html-->
<a href="{% url 'add' %}" class="btn btn-info">Add Bookmark</a>

 

5. [클래스형 뷰] Detail 구현

장고의 generic view중 DetailView를 썼다.

#views.py
from django.views.generic.detail import DetailView

class BookmarkDetailView(DetailView):
    model = Bookmark

url에 실행시킬 view를 연결시킨다.

#app/urls.py
from .views import *

urlpatterns = [
    #...
    path('detail/<int:pk>', BookmarkDetailView.as_view(), name='detail'),
]

app/templates/classapp/bookmark_detail.html을 생성한다.

DetailView가 html파일에 object로 객체를 넘겨주기 때문에, object.필드이름으로 출력하면 된다.

<!--bookmark_detail.html-->
{% extends 'base.html %}

{% block title %}Bookmark Detail{% endblock %}

{% block content %}
  {{object.site_name}}
  <br/>
  {{object.url}}
  <!-- generic view인 DetailView가 object라는 이름으로 객체를 전달한다. -->
{% endblock %}

site의 이름을 클릭했을 때 '자세히 보기' 페이지로 넘어가도록 한다.

<!--bookmark_list.html-->
<!--site이름을 클릭했을 때 detail을 보여준다.-->
<td><a href="{% url 'detail' pk=bookmark.id %}">{{bookmark.site_name}}</a></td>

 

6. [클래스형 뷰] Update 구현

장고의 generic view중 UpdateView를 썼다.

#views.py
from django.views.generic.edit import CreateView, UpdateView

class BookmarkUpdateView(UpdateView):
    model = Bookmark
    fields = ['site_name', 'url']
    template_name_suffix = "_update"
#app/urls.py

urlpatterns = [
    #...
    path('update/<int:pk>', BookmarkUpdateView.as_view(), name='update'),
]

app/templates/classapp/bookmark_update.html을 생성한다.

<!--bookmark_update.html-->

{% extends 'base.html' %}

{% block title %}Bookmark Update{% endblock %}

{% block content %}

    <form action="" method="post">
        {% csrf_token %}
        {{form.as_p}}
        <input type="submit" value="Update" class="btn btn-info btn-sm">
    </form>

{% endblock %}

list화면에서 [Modify]버튼을 눌렀을 때, bookmark_update 화면이 뜨도록 연결해주겠습니다.

<!--bookmark_list.html-->

<td><a href="{% url 'update' pk=bookmark.id %}" class="btn btn-success btn-sm">Modify</a></td>

update페이지에서 수정을 한 후 [Update]버튼을 누르면 에러가 납니다.

views.py에서 success_url을 안 알려줬기 때문인데, create할 때 해봤으니까 get_absolute_url이라는 걸 써보겠습니다.

get_absolute_url은 models.py에 쓰는 것이다.

#models.py
from django.urls import reverse

class Bookmark(models.Model):
    #...
    def get_absolute_url(self): 
        return reverse('detail', args=[str(self.id)])
	#...

 

7. [클래스형 뷰] Delete 구현

장고의 generic view중 DeleteView를 썼다.

#views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView

class BookmarkDeleteView(DeleteView):
    model = Bookmark
    success_url = reverse_lazy('list')
#models.py
urlpatterns = [
    #...
    path('delete/<int:pk>', BookmarkDeleteView.as_view(), name='delete'),
]

app/templates/classapp/bookmark_confirm_delete.html을 생성한다.

https://getbootstrap.com/ 에서 alert을 검색해서 코드 복붙하고 수정하였습니다.

{% extends 'base.html' %}

{% block title %}Confirm Delete{% endblock %}

{% block content %}

<form action="" method="post">
    {% csrf_token %}
    <div class="alert alert-danger" role="alert">
        다음의 "{{object}}"을 삭제하시겠습니까?
    </div>
    <!-- <div class="alert alert-danger">다음의 "{{object}}"을 삭제하시겠습니까?</div> -->
    <input type="submit" value="Delete" class="btn btn-danger">

{% endblock %}

list화면에서 [Delete]버튼을 눌렀을 때, bookmark_delete 화면이 뜨도록 연결해주겠습니다.

<!--bookmark_list.html-->
<td><a href="{% url 'delete' pk=bookmark.id %}" class="btn btn-danger btn-sm">Delete</a></td>

 

8. 완성된 화면

'Programming > Django' 카테고리의 다른 글

클래스형 뷰를 사용한 CRUD(2)-Bootstrap을 이용한 pagination  (0) 2021.06.23
Django 입력 받기  (0) 2021.05.31
Django API 서버 만들기  (0) 2021.04.13
REST API 서버 - 기본 세팅  (0) 2021.04.11
로그인&로그아웃  (0) 2020.08.26