View 구현의 기본 → FBV로 구현할 줄 알아야 응용이 가능하다.
공통 기능들은 장식자 문법으로 적용
@api_view(['GET'])
@throttle_classes([OncePerDayUserThrottle])
def my_view(request):
return Response({"message": "Hello for today!"})
공통 기능들은 상속 문법으로 적용
class MyView(APIView):
throttle_classes = [OncePerDayUserThrottle]
def get(self, request):
return Response({"message": "Hello for today!"})
as_view() 클래스 함수를 통해, View 함수를 생성
상속을 통해, 여러 기능들을 믹스인.
django.views.generic
https://github.com/django/django/tree/3.0.2/django/views/generic
django-braces
https://django-braces.readthedocs.io
# views.py
from django.shortcuts import get_object_or_404, render
def post_detail(request, id):
post = get_object_or_404(Post, id=id)
return render(request, 'blog/post_detail.html', {
'post': post,
})
def article_detail(request, id):
article = get_object_or_404(Article, id=id)
return render(request, 'blog/article_detail.html', {
'article': article,
})
# urls.py
urlpatterns = [
path('post/<int:id>/', post_detail),
path('article/<int:id>/', article_detail),
]
def generate_view_fn(model):
def view_fn(request, id):
instance = get_object_or_404(model, id=id)
instance_name = model._meta.model_name
template_name = '{}/{}_detail.html'.format(model._meta.app_label, instance_name)
return render(request, template_name, {
instance_name: instance,
})
return view_fn
post_detail = generate_view_fn(Post)
article_detail = generate_view_fn(Article)
generate_view_fn이라는 함수가 호출이 될 때, view_fn이라는 함수가 실행이 됨.
generate_view_fn이 호출될 때마다 로컬 함수인 view_fn은 새롭게 계속 정의됨.
class DetailView:
def __init__(self, model):
self.model = model
def get_object(self, *args, **kwargs):
return get_object_or_404(self.model, id=kwargs['id'])
def get_template_name(self):
return '{}/{}_detail.html'.format(
self.model._meta.app_label,
self.model._meta.model_name)
def dispatch(self, request, *args, **kwargs):
object = self.get_object(*args, **kwargs)
return render(request, self.get_template_name(), {
self.model._meta.model_name: object,
})
@classmethod
def as_view(cls, model):
def view(request, *args, **kwargs):
self = cls(model)
return self.dispatch(request, *args, **kwargs)
return view
post_detail = DetailView.as_view(Post)
article_detail = DetailView.as_view(Article)
# views.py
from django.views.generic import DetailView
# 보통 urlpatterns에서 pk로 받아오는데, pk로 안쓰고 id로 썼다면 밑에 코드처럼
# id로 바꿔줘야함.
post_detail = DetailView.as_view(model=Post, pk_url_kwarg='id')
article_detail = DetailView.as_view(model=Article, pk_url_kwarg='id')
# 만약 urlpatterns에서 pk로 썼다면 인자에서 pk_url_kwarg는 생략해도 무방하다.
post_detail = DetailView.as_view(model=Post)
article_detail = DetailView.as_view(model=Article)
# urls.py
urlpatterns = [
path('post/<int:pk>/', post_detail),
path('article/<int:pk>/', article_detail),
]
# 상속을 통한 CBV 속성 정의
# views.py
from django.views.generic import DetailView
# 이것 또한 url에서 pk로 받았으면 pk_url_kwarg는 따로 정의 하지 않아도 된다.
class PostDetailView(DetailView):
model = Post
pk_url_kwarg = 'id'
post_detail = PostDetailView.as_view()
필요한 설정값을 제공하거나, 특정 함수를 재정의하는 방식으로 커스텀 가능
하지만, 그 관례를 잘 이해하지 못하고 사용하거나, 그 관례에서 벗어난 구현을 하고자 할 때에는 복잡해지는 경향이 있음.
파이썬 클래스에 대한 이해가 필요 (특히 상속, 인자 packing/unpacking)
https://github.com/django/django/tree/2.1/django/views/generic