티스토리 뷰
함수 기반 뷰
지금까지 썼던 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 기능이 있는 기능을 미리 만들어서 제공한다.
이 녀석이 클래스 기반으로 만들어져 있어서 위 내용을 이해해야 한다.
제네릭뷰 사용 방법
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 = 반드시 모든 기능들이 유효할 때만 실행하고 싶을 때 불러온다.