1)
urlpatterns=[
path('', views.item_list),
path('<int:pk>/', views.post_detail),
]
프로젝트 폴더의 urls.py에서 gallery/ url을 입력했을 경우 gallery 앱의 urls.py를 include 하도록 설정해줬다.
gallery 다음 url이 int type으로 넘어올 경우 이를 pk란 이름으로 넘겨줄 것이고, views.py의 item_detail 함수-뷰(혹은 호출 가능한 객체)에서 이를 처리할 것이다.
따라서 item_detail 함수는 첫번 째 인자인 request뿐만 아니라, pk를 두번 째 인자로 받아야한다. 이를 URL captured values라고 부른다. 이 값들이 과거 사용했던 url() 혹은 re_path()에서는 문자열로 넘어오나 path()에서는 컨버터에 설정된 'int'같은 타입에 따라 다르다.
HttpRequest가 전달되기 때문에 views.py의 함수들은 명시적이든 묵시적이든 response를 반환해야 한다.
2)
ROOT_URLCONF = 'opengallery.urls'
"localhost:8000/admin"에서 '/' 앞은 웹 어플리케이션 이름을 의미하고 '/' 뒤는 처리할 로직을 의미한다. "Cool URIs don't change."란 모토아래 구현된 이런 편리한 시스템을 URL dispatcher라고 한다.
프로젝트 폴더의 settings.py에는 가장 최상위의 urlpatterns를 확인할 수 있다. urls.py에서 include로 각 앱의 urls.py를 연결시켜 줬는데 결국 어떤 트리 구조가 자리잡은 셈이다.
3)
app_name = 'gallery'
urlpatterns=[
path('', views.item_list),
path('<int:pk>/', views.item_detail),
]
views.item_list의 이름을 'item_list'로 지정하더라도 다른 앱에 같은 이름이 존재할 수 있다. 그래서 앱 자체의 이름을 app_name으로 명시해준다. URL reverse에서 namespace로 사용될 것이다.
4)
def item_detail(request, pk):
item = get_object_or_404(Item, pk=pk)
return render(request, 'gallery/item_detail.html',{
'item': item,
})
urls.py에서 pk로 넘겨 받은 인자를 queryset의 뒤쪽 pk에 넣고 이에 해당하는 (앞쪽) pk를 갖는 객체를 'item'으로 지정해서 다시 템플릿에 같은 이름으로 넘긴다.
Item.objects.get(pk=pk)로 처리할 수도 있지만, 해당하는 pk가 없는 경우에 500 에러를 발생시키는데 해당 에러는 서버 에러이므로 적합하지 않다. 이를 try-except 구조를 활용해서 raise Http404를 추가하거나 아니면 위와 같이 shortcuts의 get_object_or_404를 활용한다.
queryset을 얻고 특정 pk의 object하나를 반환하는데, get()과 마찬가지로 1개 이상의 값이 반환되면 MultipleObjectsReturned 에러가 발생한다.
클래스 기반 뷰로는 item_detail = DetailView.as_view(model=Item)이라고 간단하게 정리할 수 있다. 물론 CBV 쪽이 내부적으로 더 복잡하다.
5)
클래스형 뷰에서 request-response의 처리 진입점은 as_views()이다. 함수 내부의 함수, 그러니까 일급함수로 반환되는 view는 dispath()를 호출하는데 이는 HTTP method를 분석해서 lower()를 거쳐 GET, POST 등에 적절한 멤버 함수 get(), post() 등을 할당한다. 이 중심에 있는 기능이 handler이다.
6)
TemplateView.as_view(template_name='root.html')
위의 코딩은 먼저 as_view()의 __init__에서 **kwargs를 통해서 View 클래스의 setattr(self, key, value)로 할당된다. 예를 들어key='template_name', value='root.html'일 때 "self.template_name=root.html"으로 호출 가능성이 생기는 것 같다.
TemplateView는 View를 상속하므로 as_view() 메소드를 사용할 수 있고 이를 render하는 데는 TemplateViewMixin의 지분이 크다. 키워드 인자를 넘기는 기능은 ContextMixin의 지분이 크다.
적용하지는 않았지만, 'root.html'을 렌더링하지 않고, root page ''로 접근했을 떄 RedirectView를 이용해 /gallery/로 넘겨줄 수 있다.
/gallery/로 접근했을 때 views.item_list를 보여주는 것과 RedirectView에서 url대신 pattern_name으로 'gallery:item_list'을 입력하는 것은 같은 기능을 가진다. 이는 get_redirect_url() 메소드가 내부적으로 사용하는 reverse 함수의 기능이다. django.urls.base.py에서 확인 가능하다.
7)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'opengallery', 'templates'),
],
templates loader는 app directory와 file system으로 나눠진다. 전자는 앞선 과정에서 다뤘는데 어디에도 속하기 애매한 템플릿의 경우에는 file system template loader로 처리한다.
앱 아래 생성한 templates 폴더와 다르게 해당 폴더는 반드시 "templates"란 이름을 가질 필요는 없다고 한다.