본문 바로가기
관리자

Programming-[Backend]/Django

Django로 Pinterest 따라 만들기-8. Authentication, Decorator 활용, superuser 및 media 설정

728x90
반응형

 

1. Authentication 기능 구현

 

 

메인 페이지 접근 제한

로그인한 사용자만 메인 페이지에 접근할 수 있도록 아래 코드와 같이 접근 제한 코드를 추가한다. 특별할게 없고, 기존 코드를 if, else 문으로 감싸서 처리한다. django에서 제공해주는 requet.user.is_authenticated로 로그인 여부를 검사할 수 있다. 로그인이 되지 않았다면 HttpResponseRedirect를 이용해서 로그인 페이지로 보내도록 한다.

 

views.py

def hello_world(request):
    if request.user.is_authenticated:
        if request.method == 'POST':
		#기존 코드 생략
    else:
        return HttpResponseRedirect(reverse('accountapp:login'))

 

각 뷰 접근 제한

 

각 뷰에 접근 제한을 해본다. class로 작성했기 때문에, 상속받는 UpdateView, DeleteView에서 제공하는 get, post '메서드'를 사용할 수 있다. 참고로 파이썬에서는 class 내부의 def는 '메서드', 위 메인 페이지용 def 자체는 '함수'라고 구분한다.

 

 

views.py

각 메서드에서 is_authenticated를 사용하였다. 로그인 여부 뿐만 아니라 메서드에서 받아오는 target_user가 실제 로그인한 user와 일치하는지 여부를 확인하기 위해서 self.get_object() = self.request.user 구문을 사용하였다. self는 각 클래스를 의미하고, get_object()는 각 class에서 사용하는 model, 즉 user 객체를 가져온다.

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'

    def get(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().get(*args, **kwargs)
        else:
            return HttpResponseForbidden()

    def post(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().post(*args, **kwargs)
        else:
            return HttpResponseForbidden()


class AccountDeleteView(DeleteView):
    model = User
    context_object_name = 'target_user'
    success_url = reverse_lazy('accountapp:login')
    template_name = 'accountapp/delete.html'

    def get(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().get(*args, **kwargs)
        else:
            return HttpResponseForbidden()

    def post(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().post(*args, **kwargs)
        else:
            return HttpResponseForbidden()

 

 

또한 HttpResponseForbidden()을 사용하였다. 이제 로그인한 사용자가 다른 사용자의 update, delete 페이지로 접근하면 403 에러가 발생한다.

 

 

 


 

2. Decorator 적용하기

 

Decorator란

간단하게 말하자면 함수의 주요 기능 외 부가적인 기능들을 공통화하여 처리함으로써 코드의 가독성을 높일 수 있는 방법이다. 강의에서 드는 예시로, 어떤 함수의 실행 전과 후의 시각을 출력하는 함수가 있다고 해보자. 그러면 아래와 같이 decorator를 적용하여 반복적인 작업을 줄이고 코드의 가독성을 높일 수 있다.

 

def function():
    print(datetime.now())
    print("function process")
    print(datetime.now())
    

#decorator 적용 코드
@decorator
def function():
	print("function process")
    
#decorator 코드
def decorator(func):
	def decorated():
    	print(datetime.now())
        func()
        print(datetime.now())
    return decorated

 

@login_required, @method_decorator

django에서 기본적으로 제공하는 @login_required를 적용할 수 있다. 직관적으로 알 수 있듯이 로그인 이후에만 해당 함수 또는 메서드에 접근가능하도록 한다는 것이다.

 

메인 페이지 '함수'에 적용(views.py)

@login_required
def hello_world(request):
    if request.method == 'POST':
       #로직 생략

 

클래스뷰 '메서드'에 적용

클래스 내부에 있는 메서드에 적용하기 위해서는 @method_decorator()를 써줘야한다.

@method_decorator(login_required, 'get')
@method_decorator(login_required, 'post')
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(login_required, 'get')
@method_decorator(login_required, 'post')
class AccountDeleteView(DeleteView):
    model = User
    context_object_name = 'target_user'
    success_url = reverse_lazy('accountapp:login')
    template_name = 'accountapp/delete.html'

 

 

커스텀 데코레이터 적용

그런데 login_required는 단순히 로그인 여부만 체크할뿐, 페이지의 pk와 로그인한 유저의 pk가 일치하는지는 검사하지 않는다. 따라서 이 기능을 추가하기 위해서 커스텀 데코레이터를 만든다.

 

accountapp/decorators.py

 

User.objects.get(pk=kwargs['pk']로 키워드 인자로 'pk'라는 이름의 객체를 가져온다는 것을 아아두자.

from django.contrib.auth.models import User
from django.http import HttpResponseForbidden

def account_ownership_required(func):
    def decorated(request, *args, **kwargs):
        user = User.objects.get(pk=kwargs['pk'])
        if not user == request.user:
            return HttpResponseForbidden()
        return func(request, *args, **kwargs)
    return decorated

 

views.py

이제 @method_decorator로 커스텀 데코레이터로 작성한 account_ownership_required를 넣어주면 된다. 적용해야할 데코데이터가 여러 개라면, 최상단에 선언한 has_ownership 처럼 리스트를 만들어서 여러 개의 데코레이터를 한번에 적용하는 것도 가능하다.

has_ownership = [
    login_required, account_ownership_required
]

###중략...

# @method_decorator(login_required, 'get')
# @method_decorator(login_required, 'post')
# @method_decorator(account_ownership_required, 'get')
# @method_decorator(account_ownership_required, 'post')
@method_decorator(has_ownership, 'get')
@method_decorator(has_ownership, 'post')
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(login_required, 'get')
# @method_decorator(login_required, 'post')
# @method_decorator(account_ownership_required, 'get')
# @method_decorator(account_ownership_required, 'post')
@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'

 

 


 

3. Superuser 및 media 설정

 

다음 강의를 위한 세팅 부분이라고 보면 된다.

 

SuperUser

 

계정생성

superuser를 생성하기 위해서 'pyhton manage.py createsuperuser' 명령어를 터미널에 입력하고 username, password를 설정한다.

 

그리고 pragmatic/urls.py에 기본으로 설정된 admin 페이지에 접속해본다.

 

로그인을 하면 관리자 페이지가 나오고, 기본적으로 생성돼있던 Model들이 보인다. 앞으로 사이트를 구축하면서 모델들이 추가되면 여기서 다 조회가 된다고 한다. 그리고 django에서 제공해주는 이 기본 admin 페이지의 기능도 상당히 좋아서, 살펴보면 상당한 내용들이 있다고 한다.

 

 

 

MEDIA 설정

마지막으로 MEDIA 설정을 한다. static과 같이 media 파일들을 올릴 때 기본이 되는 MEDIA_URL과 media 파일들이 모이는 MEDIA_ROOT 위치를 설정해준다.

 

settings.py 일부

MEDIA_URL = 'media/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

 

그리고 Media 파일은 git에 올라갈 필요가 없으므로 .gitignore에 추가해준다.

 

gitignore에 추가

media/

 


 

참조

1. 작정하고 장고! Django로 Pinterest 따라만들기 : 바닥부터 배포까지-박형석님 인프런 강의

https://www.inflearn.com/course/%EC%9E%A5%EA%B3%A0-%ED%95%80%ED%84%B0%EB%A0%88%EC%8A%A4%ED%8A%B8/dashboard

 

728x90
반응형