티스토리 뷰

반응형

함수 기반 뷰

 

지금까지 썼던 views.py가 이런 것에 해당한다.

def my_view(request):
	if request.method == 'GET'
    	#서비스 처리
       	return HttpResponse('result')

후에 urls.py에서 path를 추가

 

그러나 만약에 view 안에 있는 내용이 너무 많다면 이걸 클래스로 구현해도 된다.

 

클래스 기반 뷰

class django.views.generic.base.View를 상속받음

View는 모든 클래스형 뷰의 기본이 되는 최상위 뷰

참조 문서https://docs.djangoproject.com/en/4.2/ref/class based views/base/#view
소스코드 https://github.com/django/django/blob/stable/4.2.x/django/views/generic/base.py

 

class MyView(View):
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            return self.dispatch(request, *args, **kwargs)
        return view

클래스 이름.as_view로 실행

 

as_view가 classonlymethod에 들어가서 실행된다.

문제는 url에서 클래스가 실행이 되야 하는데, 메소드가 실행이 되어야 한다.

 

path('about/', views.my_view) 라고 하면, 실행이 안된다.

그래서, as_view를 사용해서, as_view에서 리턴하는 내장함수 view를 사용한다.

from .views import MyView

path('about/', MyView.as_view())

 

dispacth 메소드가 실행이 된다.

 

제네릭 뷰

별도의 view 구현 없이 바로 사용할 수 있다.

필요한 경우 제네릭 뷰를 상속하여 속성과 메소드를 오버라이딩하여 커스터마이징할 수 있다.

 

참조문서https://docs.djangoproject.com/en/4.2/ref/class based views/
소스코드 https://github.com/django/django/tree/4.2/django/views/generic

 

CRUD 기능이 있는 기능을 미리 만들어서 제공한다.

이 녀석이 클래스 기반으로 만들어져 있어서 위 내용을 이해해야 한다.

 

https://ccbv.co.uk/

 

제네릭뷰 사용 방법

1. as_view 메소드의 키워드 인자로 지정하는 방법

2. 제네릭뷰를 상속받은 클래스에서 지정하는 방법

 

as_view() 인자로 지정

 

urls.py

from django.views.generic import ListView

urlpatterns =[
	path('list/', ListView.as_view(model=Book))
]

 

제네릭 뷰 상속

views.py에서 상속

from django.views.generic import ListView

class MyView(ListView):
	model =Book

그리고 url.py에 추가한다.

from .views import MyView

urlpatterns =[
	path('list/', Myview.as_view())
]

 

Generic Display View의 종류

ListView는 model 속성에 지정된 모델의 모든 인스턴스들을 추출한 후 템플릿에 컨텍스트로 전달한다.

 

Post.objects.all()로 응답한다.

기본으로 응답하는 템플릿은 Post_list.html 

 

book 앱을 생성하고, 

book 앱을 settings 에서 등록한다.

 

book/models.py에 다음과 같은 내용을 추가한다.

from django.db import models
from django.urls import reverse
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=100)
    publisher = models.CharField(max_length=100)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('book:list')

 

그리고 book 앱을 migration

python manage.py makemigrations book
python manage.py migrate book

book 모델에 일단 데이터를 추가한다.

장고쉘에서 실

from book.models import Book
for i in range(1, 11):
	Book.objects.create(title=f'제목{i}', author=f'저자{i}’,
		publisher=f'출판사{i}')
Book.objects.count()

 

book 앱의 url을 mysite urls.py에 입력한다.

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("blog/", include('blog.urls')),
    path("book/", include('book.urls')),
    path("gallery/", include('gallery.urls')),
    path("accounts/", include('accounts.urls')),

    
]

 

그리고 book/urls.py를 만들어서 다음과 같은 내용을 채워넣는다.

from django.urls import path, reverse, reverse_lazy
from django.views.generic import *
from .models import Book

app_name ='book'
urlpatterns = [
    path('', ListView.as_view(model=Book), name='list'),
    path('detail/<pk>/', DetailView.as_view(model=Book), name='detail'),
    path('create/', CreateView.as_view(model=Book, fields='__all__'), name='create'),
    path('update/<pk>/', UpdateView.as_view(model=Book, fields='__all__'), name='update'),
    path('delete/<pk>/', DeleteView.as_view(model=Book, success_url=reverse_lazy('book:list')), name='delete'),
]

이곳이 핵심

 

gerneric view를 끌고 와서, as_view에 있는 내용을 채워넣는다.

model은 앱 이름으로 줘야 한다. 그리고field는 모든 필드로 지정한다.

 

 

거의 다 왔다.

이제 마지막으로 book 앱의 템플릿을 만들면 된다.

 

book/templates/book/book_list.html

{% extends "layout.html" %}
{% block title %} Book 목록 {% endblock %}
{% block content %}
    <h1>Book 목록 보기</h1>
    {% for book in book_list %}
        <a href="{% url 'book:detail' book.id %}"> {{book.title}}</a><br>
    {% endfor %}
{% endblock %}

아무것도 안하면, 제너릭 뷰의 기본 테믚ㄹ릿명이 앱 이름/모델명 소문자_list와

앱이름/모델명 소준자_detail이 된다.

 

book/templates/book/book_detail.html

{% extends "layout.html" %}
{% block title %} Book 상세보기 {% endblock %}
{% block content %}
    <h1>{{book.title}}</h1>
    제목 : {{book.title}} <br>
    저자 : {{book.author}} <br>
    출판사 : {{book.publisher}} <br>
{% endblock %}

 

이러면 이제 /book으로 접속했을 때, 페이지가 나온다.

 

Generic Edit View

createView는 데이터 추가 기능이 구현된 제너릭 뷰로서, 장고 from을 기반으로 동작된다.

 

get 방식 요청시, template_name 속성에 지정된 템플릿 또는 미지정시 앱이름/모델명소문자_form.html 템플릿을 응답한다.

 

POST 방식 요청시

GET 방식 요청으로 응답받은 입력페이지에서 값을 입력한 후, SUBMIT 버튼을 클릭하면 요청되는 방식

유효성 검사 성공시 : 입력값을 DB에 추가하고 success_url에 지정된 URL로 이동

유효성 검사 실패시 : 오류 메시지와 함께 입력 페이지로 이동

 

path('create/', CreateView.as_view(model=Book, fields='__all__'), name='create'),

 

템플릿에서 다음과 같은 내용을 추가한다.

book_form.html

{% extends 'layout.html' %}
{% block title %}
  Book 등록
{% endblock %}
{% block content %}
  <h1>Book 등록</h1>
  <form action="" method="POST">
    {% csrf_token %}
    <table>{{ form.as_table }}</table>
    <input type="submit" value="등록" />
  </form>
{% endblock %}

 

당연히 book_list.html에서도 새 책 등록을 추가해줘야 한다.

<a href="{% url 'book:create' %}">[새 책 등록]</a>

 

UpdateView / DeleteView

get 방식 요청시

앱이름/모델명소문자_form.html 템플릿을 응답

 

post 방식 요청시

GET 방식 요청으로 응답받은 입력페이지에서 값을 입력한 후, SUBMIT 버튼을 클릭하면 요청되는 방식

유효성 검사 성공시 : 입력값을 DB에 추가하고 success_url에 지정된 URL로 이동

유효성 검사 실패시 : 오류 메시지와 함께 입력 페이지로 이동

 

path('update/<pk>/', UpdateView.as_view(model=Book, fields='__all__'), name='update'),
path('delete/<pk>/', DeleteView.as_view(model=Book, success_url=reverse_lazy('book:list')), name='delete'),

 

똑같이 url.py에 추가

 

book_detail에 수정하기 버튼을 추가해줘야 한다.

 

<a href="{% url 'book:update' book.id %}">[수정하기]</a>
<a href="{% url 'book:delete' book.id %}">[삭제하기]</a>

 

유의할 점이 하나 있는데, reverse와 reverse lazy를 구별해야 한다.

path('delete/<pk>/', DeleteView.as_view(model=Book, success_url=reverse('book:list')), 
	name='delete'),
->오류 발생
path('delete/<pk>/', DeleteView.as_view(model=Book, 
	success_url=reverse_lazy('book:list')), name='delete'),
->오류 해결

 

 

reverse라는 값을 모르면 안된다. 아직 path name을 인식하지 못한 상태에서 실행되면 인식하지 못한다.

실제 클라이언트로부터 들어왔을 때 실행하라는 명령어로 바꿔준다.

 

reverse는 서비스가 준비가 될 때,

reverse lazy는 서비스가 실제 사용될 때 사용된다.

 

 

이제 delte도 html을 만들어주면 된다.

book_confirm_delete.html

{% extends "layout.html" %}
{% block title %}Post 삭제{% endblock %}
{% block content %}
    <h1> BOOK 삭제</h1>

    "{{book}}"을 정말로 삭제하시겠습니까?
    <form action="" method="POST">
        {% csrf_token %}
        <input type="submit" value="네, 삭제합니다">
    </form>
    <a href="{% url 'book:list'%}">아니오, 취소합니다</a>
    
{% endblock %}

 

form_valid = 반드시 모든 기능들이 유효할 때만 실행하고 싶을 때 불러온다.

 

 

반응형