
decorator 정의
어떤 함수를 인자로 받아서 그 함수를 앞뒤(혹은 앞만, 뒤만)꾸며줄 수 있는 방식

decorator 적용
@decorator를 붙여주어 적용.

우리의 코드
겹치는 부분을 decorator 를 이용할 것.

if request.user.is_authenticated: # 로그인을 한 경우와 else: # 로그인을 하지 않은 경우를 decorator로 만들어주기
from django.contrib.auth.decorators import login_required
...
@login_required # 추가
def hello_world(request):
if request.method == "POST":
temp = request.POST.get('hello_world_input')
new_hello_world = HelloWorld()
new_hello_world.text = temp
new_hello_world.save()
return HttpResponseRedirect(reverse('accountapp:hello_world'))
else:
hello_world_list = HelloWorld.objects.all()
return render(request, 'accountapp/hello_world.html', context={'hello_world_list': hello_world_list})
로그인이 안되어있는 상태에서 hello_world로 이동
로그인 창으로 redirect 되는 것을 볼 수 있다 -> decorator가 작동하고 있다.
def get(self, *args, **kwargs):에서 get 은 클래스 안에 있는 메소드 이기 때문에 함수에서의 decorator 적용 방법과는 약간 다르다.
일반 함수를 사용하는 decorator 를 클래스 내부의 메소드에 사용할 수 있도록 변환
자신인지 확인하는 인증 과정은 아직 추가 안했음.
from django.utils.decorators import method_decorator
...
# 일반 함수를 사용하는 decorator 를 클래스 내부의 메소드에 사용할 수 있도록 변환해야한다 -> method_decorator
# 인자 : (일반 함수 decorator, 우리가 적용할 메소드(get, post 이런 식의 http 메소드를 의미))
@method_decorator(login_required, 'get')
@method_decorator(login_required, 'post')
class AccountUpdateView(UpdateView):
...
자신인지 확인하는 인증 과정을 추가하기 위해서 custom decorator를 하나 만들어야 함.
pragmatic/accountapp/decorators.py 파일 생성
다음과 같이 작성하면 이전 강의에서 작성했던 인증 시스템과 동일하게 작동
# pragmtic/accountapp/decorators.py
from django.contrib.auth.models import User
from django.http import HttpResponseForbidden
def account_ownership_required(func): # decorator 정의 (이 계정의 소유권이 필요하다는 이름)
def decorated(request, *args, **kwargs): # request 를 받아
# 우리가 원하는 작업 - 본인인지 확인하는 작업
# get, post 등의 요청을 받으면서 pk 로 받은 값을 가지고 있는 User 객체가 user 가 되는 것
user = User.objects.get(pk=kwargs['pk'])
# pk 를 확인해서 그 User 객체가 실제로 request 를 보낸 user 와 같은지 아닌지 확인
if not user == request.user: # 유저가 아니라면
return HttpResponseForbidden()
return func(request, *args, **kwargs) # 요청 보낸 유저와 유저 객체(pk값확인)가 같은 경우는 그냉 보내주기
return decorated
#account_ownership_required 라는 decorator 를 만들었으니까 views.py에 적용하기
# pragmatic/accountapp/views.py
from accountapp.decorators import account_ownership_required
has_ownership = [account_ownership_required, login_required] # 하나의 배열로 만들어주기
...
@method_decorator(has_ownership,'get') # has_ownership 이라는 배열 내에 있는
@method_decorator(has_ownership,'post') # decorator 들을 모두 확인을 하고 체크 해줌.
class AccountUpdateView(UpdateView):
model = User
context_object_name = 'target_user'
form_class = AccountUpdateForm
success_url = reverse_lazy('accountapp:hello_world')
template_name = 'accountapp/update.html'
@method_decorator(has_ownership,'get')
@method_decorator(has_ownership,'post')
class AccountDeleteView(DeleteView):
model = User
context_object_name = 'target_user'
success_url = reverse_lazy('accountapp:login')
template_name = 'accountapp/delete.html'
로그인을 하지 않은 상태에서 1번 계정의 탈퇴 페이지로 이동
127.0.0.1:8000/accouns/delete/1을 입력하면 엑세스가 거부된다고 뜬다.
로그인 한 상태에서 1번 계정의 탈퇴 페이지로 이동
마찬가지로 엑세스가 거부된다고 뜬다.
로그인 한 계정(3번)의 탈퇴 페이지는 정상적으로 이동
127.0.0.1:8000/accouns/delete/3을 정상적으로 작동한다.
git add ., git commit -m "django course 28 commit을 통해 커밋한다.