이 키워드로 검색하는 사람들은 장고 클래스뷰 하다가, 주화입마에 빠져들고 있는 사람일 것이다.
중간 결론
CreateView, UpdateView, FormView 등에서 모델 폼을 사용할 때,
- get 인 경우, get_context_data() 오버라이딩
- post 면, form_valid()
- 공통인 경우, dispatch() 오버
https://github.com/django/django/blob/main/django/views/generic/edit.py
GitHub - django/django: The Web framework for perfectionists with deadlines.
The Web framework for perfectionists with deadlines. - GitHub - django/django: The Web framework for perfectionists with deadlines....
github.com
장고 기초 문법만 하면, html 도 잘 몰라도 할 수 있다는 걸 강조한 책.. ㅠㅠ Do it 장고 예제 중,
포스트 업데이트를 하는 클래스 뷰인데,
게시글, 소위 object 인데,
get_context_data 에서는 self.object
dispatch() 에서는 self.get_object()
form_valid() 에서는 self.object 로 사용하고 있다. 아씽. 아호.... ㅠㅠ 띵 받아.
class PostUpdate(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category']
template_name = 'blog/post_update_form.html'
# GET 일 때,
def get_context_data(self, **kwargs):
context = super(PostUpdate, self).get_context_data()
if self.object.tags.exists():
.....
# url로부터 요청 받을 때, 공통
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and request.user == self.get_object().author:
.....
# POST 일 때,
def form_valid(self, form):
response = super(PostUpdate, self).form_valid(form)
self.object.tags.clear()
......
장고 소스를 보면, self.object = self.get_object() 가 있는데,
이 말은 self.get_object() 가 먼저 실행되야 한다는 것이잔아.
- 모든 클래스뷰에서는 url 을 입력받으면, 클래스.as_view() 메서드로 해당 클래스의 dispatch() 를 호출한다.
- dispatch 는 http 메소드를 확인 후, def get(), def post() 등으로 분기해준다.
- 분기
- GET : dispatch() -> get -> get_context_data() -> get_initial()
- POST :dispatch() -> post -> get_initial() -> form_valid() -> get_success_url()
그래서, 유저가 작성자와 동일한지를 먼저 검사하기 위해, dispatch() 에 오버라이딩한 것이고,
get_object().author 를 한 이유는 .....?
dispatch() 단계에서는 self.object = self.get_object() 메서드가 실행되지 않았기 때문일거다라는 합리적인 추측.... 조금 더 찾아봤는데, 일단 확실해보인다.
어 그러네.... dispatch 이후, get, post 에서 수행되는거였어.
왜 내가 본 책에는 이런 설명이 없었을까... 아후.
게다가 대부분 답변들도 그냥 dispatch 소스를 보면 알 수 있다 정도로 얘기하는데,
핵심은 클래스별, 그리고, 각 수행 조건별로 메소드 실행 단계가 다르다는 거였잔아.
아흐. 빡친당
장고는 쉬운게 절대 ... 네버 네버 아니다. 특히, 클래스뷰.
근데, 함수형만 쓴다 가정하면, 다른 언어나 프레임웍 대비해서 장고의 장점이 뭐냐?
순간 또 빡치는 넋두리. ㅠ
class BaseDetailView(SingleObjectMixin, View):
"""A base view for displaying a single object."""
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
class BaseUpdateView(ModelFormMixin, ProcessFormView):
"""
Base view for updating an existing object.
Using this base class requires subclassing to provide a response mixin.
"""
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super().post(request, *args, **kwargs)
모델 폼의 주요 메소드 호출 순서
GET | POST |
dispatch() get_context_data() get_initial() |
dispatch() get_initial() form_valid() get_success_url() |
** dispatch() 가 공통적으로 호출되기 때문에, dispatch() 를 오버라이딩 한다.
# url로부터 요청 받을 때, 공통
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and request.user == self.get_object().author:
GET 메소드 요청 시 주요 메소드의 호출 순서이다.
- dispatch()
- get_context_data()
- get_initial()
POST 메소드 요청 시 주요 메소드의 호출 순서이다.
- dispatch()
- get_initial()
- form_valid()
- get_success_url()
여기서 중요한 것은
POST 요청 시에는 get_context_data() 메소드가 호출되지 않는다
GET 요청 시에는 폼 데이터를 전송 받지 못했으므로 form_valid() 메소드는 호출되지 않는다.
GET, POST 요청에서 공통된 작업을 하고자 할 경우 get_initial() 메소드를 이용할 수 있다.
다만 이 메소드는 FormMixin의 메소드이기 때문에 CreateView, UpdateView, FormView 에서만 사용가능
앱 전체 뷰에서 공통으로 호출되길 원한다면 dispatch() 메소드를 오버라이딩해야 한다
def dispatch(self, request, *args, **kwargs):
object = self.get_object()
if object.author != request.user:
messages.warning(request, '수정할 권한이 없습니다.')
return HttpResponseRedirect('/')
# 삭제 페이지에서 권한이 없다! 라고 띄우거나
# detail페이지로 들어가서 삭제에 실패했습니다. 라고 띄우거나
else:
return super(CommentUpdate, self).dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
object = self.get_object()
if object.author != request.user:
messages.warning(request, '삭제할 권한이 없습니다.')
return HttpResponseRedirect('/')
else:
return super(CommentDelete, self).dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
object = self.get_object()
if request.method == "POST":
super().post(request, *args, **kwargs)
else:
super().post(request, *args, **kwargs)
get_initail() 예시가 많아 보이진 않는데...CreateView를 상속해서 사용시, 폼에 디폴트값을 입력할 때 사용할 수 있다.
def get_initial(self):
initial = super().get_initial()
if 'category' in self.kwargs:
category = self.kwargs['category']
initial['category'] = Category.objects.filter(name=category)[0]
return initial
'erp 도전' 카테고리의 다른 글
invalid literal for int() with base 10: b'00:00:00' (0) | 2023.05.02 |
---|---|
장고 messages.add_message(request, ) (0) | 2023.05.01 |
상품 복사 구현 1)js전체선택, 폼 인풋 리스트 가져오기, 날짜(듀프,요일 체크) (0) | 2023.05.01 |
주화입마에 빠져서, 기본기 다지기를 병행하기로 (0) | 2023.04.28 |
일정표 구현 4) 수정/삭제 (0) | 2023.04.26 |
레코드 복사, 반복문 추가, bulk_update 등 (0) | 2023.04.26 |
장고 마이그레이션 에러 / 복구 showmigrations (0) | 2023.04.26 |
일정표 구현 3: 조/중/석 구분값으로 저장, 사용하기 (0) | 2023.04.25 |
댓글