티스토리 뷰

장고의 뷰는 요청 객체를 받고 응답 객체를 반환하는 내장 함수

 

함수 기반 뷰는 뷰 함수 자체가 내장 함수이고, 클래스 기반 뷰는 뷰 클래스가 내장 함수를 반환하는 as_view() 클래스 메서드를 제공.

 

django.views.generic.View에서 해당 메커니즘이 구현되며 모든 클래스 기반 뷰는 이 클래스를 직간접적으로 상속받아 이용

 

장고는 요즘 대부분의 웹 프로젝트에서 이용되는 제네릭 클래스 기반 뷰(generic class-based view, GCBV)를 제공.

 

...더보기

장고의 기본형을 보면 제네릭 클래스 기반 뷰를 위한 중요한 믹스인들이 빠져 있다. 예로 인증(Authentication) 부분 같은 것을 들 수 있다. 하지만 django-braces 라이브러리를 이용함으로써 이런 부분을 해결할 수 있다. 

가이드라인

  • 뷰 코드의 양은 적으면 적을수록 좋다.
  • 뷰 안에서 같은 코드를 반복적으로 이용하지 말라
  • 뷰는 프레젠테이션 로직에서 관리하도록 하자. 비즈니스 로직은 모델에서 처리. 매우 특별한 경우에는 폼에서 처리
  • 뷰는 간단 명료해야 한다.
  • 403, 404, 500 에러 핸들링에 클래스 기반 뷰는 이용하지 않는다. 대신 함수 기반 뷰를 이용하자.
  • 믹스인은 간단 명료해야 한다.

믹스인 이용하기

프로그래밍에서 믹스인이란 실체화된 클래스가 아니라 상속해 줄 기능들을 제공하는 클래스를 의미. 실체화(instantiation)된 상태를 의미하지는 않는다. 프로그래밍 언어에서 다중 상속을 해야 할 때 믹스인을 쓰면 클래스에 더 나은 기능과 역활을 제공할 수 있다.

 

상속에 관한 규칙

  1. 장고가 제공하는 기본 뷰는 '항상' 오른쪽에서 진행
  2. 믹스인은 기본 뷰에서부터 왼쪽으로 진행
  3. 믹스인은 파이썬의 기본 객체 타입을 상속해야한 한다.
from django.views.generic import TemplateView


class FreshFruitMixin(object):
	def get_context_data(self, **kwargs):
    	context = super(FreshFruitMixin, self).get_context_data(**kwargs)
        context['has_fresh_fruit'] = True
        return context
        

class FruityFlavorView(FreshFruitMixin, TemplateVeiw):
	template_name = "fruity_flavor.html"

어떤 장고 제네릭 클래스 기반 뷰를 이용할 것인가?

나열된 뷰들은 모든 django.views.generic이라는 접두사를 포함

 

이름 목적
View 어디에서든 이용 가능한 뷰
RedirectView 사용자를 다른 URL로 리다이렉트
TemplateView 장고 HTML 템플릿을 보여줄 때
ListView 객체 목록
DetailView 객체를 보여줄 때
FormView 폼 전송
CreateView 객체를 만들 때
UpdateView 객체를 업데이트 할 때
DeleteView 객체를 삭제
generice data view 시간 순서로 객체를 나열해 보여줄 때 

일반적인 팁

 

인증된 사용자에게만 접근 가능하게 하기

from django.views.generic import DetailView

from braces.views import LoginRequiredMixin

from .models import Flavor

class FlavorDetailView(LoginRequiredMixin, DetailView):
	model = Flavor
  • LoginRequiredMixin은 가장 왼쪽에 위치
  • 베이스 뷰 클래스는 항상 가장 오른족에 위치

순서를 잘못된 순서로 나열하면 예상치 못한 결과를 초래

 

유용한 폼을 이용하여 커스텀 액션 구현하기

from django.views.generic import CreateView

from braces.views import LoginRequiredMixin

from .models import Flavor


class FlavorCreateView(LoginRequiredMixin, CreateView):
	model = Flavor
    fields = ('title, 'slug', 'scoops_remaining')
    
    def form_valid(self, form):
    	# 커스텀 로직이 이곳에
        return super(FlavorCreateView, self).form_valid(form)

form_valid()의 반환형은 django.http.HttpResponseRedirect 가 된다.

 

부적합한 폼을 이용하여 커스텀 액션 구현하기

form_invalid()는 django.http.HttpResponse를 반환

from django.views.generic import CreateView

from braces.views import LoginRequiredMixin

from .models import Flavor


class FlavorCreateView(LoginRequiredMixin, CreateVeiw):
	model = Flavor
    
    def form_invalid(self, form):
    	# 커스텀 로직이 이곳에 위치
        return super(FlavorCreateView, self).form_invalid(form)

뷰 객체 이용하기

콘텐츠를 렌더링하는 데 클래스 기반 뷰를 이용한다면 자체적인 메서드와 속성을 제공하는 뷰 객체를 이용하여 다른 메서드나 속성(properties)에서 호출이 가능하게 하는 방법을 고려해 볼 수 있다. 이런 뷰 객체들은 템플릿에서도 호출 할 수 있다.

from django.utils.functional import cached_property
from django.views.generic import Updateview, Templateview

from braces.views import LoginRequiredMixin

from .models import Flavor
from .tasks import update_users_who_favorited


class FavoriteMixin(object):
	@cached_property
    def likes_and_favorites(self):
    	""" likes와 favorites의 딕셔너리를 반환 """
        likes = self.object.likes()
        return {
        	"likes" likes,
            "favorites": favorites,
            "favorites_count": favorites.count(),
        }
        

class FlavorUpdateView(LoginRequiredMixin, FavoriteMixin, UpdateView):
	model = Flavor
    fields = ('title', 'slug', 'scoops_remaining')
    
    def form_valid(self, form):
    	update_users_who_favorited(
        	instance=self.object,
            favorites=self.likes_and_favorites['favorites']
        )
        return super(FlavorUpdateView, self).form_valid(form)
        

class FlavorDetailView(LoginRequriedMixin, FavoriteMixin, TemplateView):
	model = Flavor
{# flavors/base.html #}
{% extends "base.html" %}

{% block lieks_and favoites %}
<ul>
	<li>Lies: {{ view.likes_and_favorites.likes }}</li>
    <li>Favorites: {{ view.likes_and_favorites.favorites_count }}</li>
</ul>
{% endblock likes_and_favorites %}

폼 사용하기

# models.py
from django.urls import reverse
from django.db import models


STATUS = (
	(0, "zero"),
    (1, "one"),
)


class Falvor(models.Model):
	title = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)
    scoops_remaining = modles.IntegerField(default=0, choices=STATUS)
    
    def get_absolute_url(self):
    	return reverse("flavors:detail", kwargs={"slug": self.slug})
# views.py
from django.contrib import messages
from django.views.generic import CreateView, UpdateView, DetailView

from braces.views import LoginRequiredMixin

from .models import Flavor


class FlavorActionMixin(object):
	fields = ['title, 'slug', 'scoops_remaining']
    
    @property
    def success_msg(self):
    	return NotImplemented
        
    def form_valid(self, form):
    	messages.info(self.request, self.success_msg)
        return super(FlavorActionMixin, self).form_valid(form)


class FlavorCreateView(LoginRequiredMixin, FlavorActionMixin, CreateVeiw):
	model = Flavor
    fields = ['title', 'slug', 'scoops_remaining']
    success_msg = 'Flavor created!"
    
    
class FlavorUpdateView(LoginRequiredMixin, FlavorActionMixin, UpdateView):
	model Flavor
    fields = ['title', 'slug', 'scoops_remainig']
    success_msg = 'Flavor updated!'
    

class FlavorDetailView(DetailView):
	modle = Flavor
...더보기

믹스인은 object를 상속해야 한다.

믹스인은 가능한 한 아주 단순한 상속의 연결이 되어야 한다.

{# flavor_detail.html #}
{% if messages %}
	<ul class="messages">
    	{% for message in messages %}
        <li id="message_{{ forloop.counter }}"
        	{% if message.tags %} class="{{ message.tags }}"
            	{% endfi %}>
            {{ message }}
        </li>
        {% endfor %}
    </ul>
{% endif %}

django-braces

 

Welcome to django-braces’s documentation! — django-braces 1.13.0 documentation

© Copyright 2013, Kenneth Love and Chris Jones Revision b81045f3.

django-braces.readthedocs.io

Decorating class-based views

 

Introduction to class-based views | Django documentation | Django

Django The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

'Django' 카테고리의 다른 글

queryset  (0) 2019.07.15
Angular4  (0) 2019.07.14
Class ListView()  (0) 2019.07.13
TypeError  (0) 2019.07.12
장고 폼의 기초  (0) 2019.07.11
최근에 올라온 글
글 보관함