내가 보려고 만든 django 분석 - 4 (views.py )

sihwan_e·2021년 6월 3일
1

Django

목록 보기
16/21

제너릭 뷰

장고에서 기본적으로 제공하는 View Class
Class View(CBV)에 해당한다.

CBV

상속과 믹스인 기능을 이용하여 코드 재사용하고 뷰를 체계적으로 구성할 수 있다.
GET, POST 등 HTTP 메소드에 따른 처리 코드를 작성할 때 if 함수 대신에 메소드 명으로 코드의 구조가 깔끔하다.
다중상속 같은 객체지향 기법을 활용해 제너릭 뷰, 믹스인 클래스 등을 사용해 코드의 재사용과 개발 생산성을 높여준다.

제너릭 뷰의 4가지 분류

기반 뷰(Base View): 뷰 클래스를 생성하고 다른, 제너릭 뷰의 부모 클래스가 되는 기본 제너릭 뷰
제너릭 보기 뷰(Generic Display View): 객체의 목록 또는 하나의 객체 상세 정보를 보여주는 뷰
제너릭 수정 뷰(Generic Edit View): 폼을 통해 객체를 생성, 수정, 삭제하는 기능을 제공하는 뷰
제너릭 날짜 뷰(Generic Date View): 날짜 기반 객체의 연/월/일 페이지로 구분해 보여주는 뷰

BaseView 만들어 보기

from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views import View

@method_decorator(csrf_exempt, name = 'dispatch')
class BaseView(View):

    @staticmethod
    def response(data={}, message='', status=200):
        result = {
            'data' : data,
            'message' : message,
        }
        return JsonResponse(result, status = status)

@method_decorator

@method_decorator 는 name 값을 지정함으로서 클래스 메소드에 대해서 해당 decorator 를 사용할 수 있다.

The @method_decorator decorator transforms a function decorator into a method decorator so that it can be used on an instance method.

클래스 내의 메서드에는 바로 데코레이터를 적용할수가 없다.
CBV의 모든 인스턴스마다 데코레이팅을 하고 싶다면, 클래스 자체를 데코레이팅 할 필요가 있다.
method_decorator 데코레이터는 function데코레이터를 method decorator으로 변환 시켜주어 인스턴스 메소드에도 사용할 수 있게 해준다.

method_decorator*args**kwargs를 클래스의 데코레이팅 된 메소드에 파라미터로 넘겨준다.

def as_view(cls, **initkwargs):
	.
    	.
    	.
    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

as_view메소드는 뷰클래스의 초기화와 핸들러를 반환하는 기능을 제공한다.

Handler

로거에 있는 메시지에 어떤 작업을 할지 결정하는 엔진이다. 로그 레코드의 로그 레벨이 핸들러의 로그 레벨보다 더 낮으면 핸들러는 메시지를 무시한다.

getattr(object, name[, default])

object에 존재하는 속성의 값을 가져온다.

dispatch

요청을 받고 HTTP 응답을 반환하는 메서드이다. GET 요청은 get()으로, POST 요청은 post() 메서드로 호출한다.

@staticmethod

정적 메서드는 매개변수에 self를 지정하지 않는다.그래서 인스턴스 속성에는 접근할 수 없다. 정적 메서드는 메서드의 실행이 외부 상태에 영향을 끼치지 않는 순수 함수(pure function)를 만들 때 사용한다. 순수 함수는 입력 값이 같으면 언제나 같은 출력 값을 반환합니다.
즉, 정적 메서드는 인스턴스의 상태를 변화시키지 않는 메서드를 만들 때 사용합니다.

베이스뷰를 만드는 이유는 앞으로 생성할 view들에서 중복되는 부분을 막아 개발 생산성을 높히고, 코드의 재사용성을 높이려는 제너릭뷰의 이용 목적에 따른 것이다.

response 함수는 dic형태의 data와 message를 파라메터로 받아 json형태로 되어진 result를 반환한다.

Json

Javascript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 기반의 표준 포맷이다.

웹개발에선 UI는 Javascript를 사용하고, 내부 application 로직은 python 으로 개발하는 경우가 많은데, javascript와 python 사이 데이터를 주고 받을 때 위와 같이 json 변환을 이용한다.

dict의 type 는 dict 이지만, json의 type는 str 이다.
그래서 키값으로 접근을 못한다.

json_val = json.dumps(dict1) (dict -> json)
dict2 = json.loads(json_val) (json -> dict)

from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views import View
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.core.validators import validate_email, ValidationError
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required


@method_decorator(csrf_exempt, name='dispatch')
class BaseView(View):

    @staticmethod
    def response(data={}, message='', status=200):
        result = {
            'data': data,
            'message': message,
        }
        return JsonResponse(result, status=status)


class UserCreateView(BaseView):
    def post(self, request):
        username = request.POST.get('username', '')
        if not username:
            return self.response(message="아이디를 입력해주세요", status=400)
        passwrod = request.POST.get('password', '')
        if not password:
            return self.response(message="패스워드를 입력해주세요", status=400)
        email = request.POST.get('email', '')
        try:
            validate_email(email)
        except ValidationError:
            return self.response(message="올바른 이메일을 입력해주세요", status=400)

        try:
            user = User.objects.create_user(username, email, password)
        except IntegrityError:
            return self.response(message='이미 존재하는 아이디입니다.', status=400)

        return self.response({'user.id': user.id})


class UserLoginView(BaseView):
    def post(self, request):
        username = request.POST.get('username', '')
        if not username:
            return self.response(message='아이디를 입력해주세요.', status=400)
        password = request.POST.get('password', '')
        if not password:
            return self.response(message='패스워드를 입력해주세요.', status=400)

        user = authenticate(request, username=username, password=password)
        if user is None:
            return self.response(message='입력 정보를 확인해주세요.', status=400)
        login(request, user)
        return self.response()


class UserLogoutView(BaseView):
    def get(self, request):
        logout(request)
        return self.response()

간단한 회원가입, 로그인, 로그아웃 view인데 이번엔 django에서 기본을 제공하는 login, logout을 이용한다.

특별히 살펴볼 것은 그다지 없지만

request.POST.get('username', '')
request.GET.get('username', '')

request.POST 는 request의 POST 값들을 dictionary 형태로 반환해 준다.
python 에서 dict은 ['key']을 이용하면 ‘key’에 해당하는 값('value')을 리턴해 주고 존재하지 않으면 KeyError를 발생시킨다.

.get('key')

dict에서 특정 key의 값을 얻는 다른 방법
.get('key') 을 이용하면 존재하지 않은 key일 경우 None을 반환해준다.
.get('key', 'defaultvalue') 와 같이 key 값이 없을 경우 default 값을 설정해 줄 수 있다.

user = authenticate()

django.contrib.auth에는 django의 인증 체계들이 들어가 있다.
authenticate(request=None, **credentials)
request와 credentuas 인자들을 받아 유효하면 user객체 반환.

create_user()

UserManager 클래스에 속해있는 함수로서 유저를 생성한다.

def create_user(self, username, email=None, password=None, **extra_fields):

super()

  • 자식 클래스에서 부모클래스의 내용을 사용하고 싶을경우 사용
@method_decorator(login_required, name='dispatch')
class HomeView(TemplateView):

    template_name = 'home.html'

    def get_context_data(self, **kwargs):
        context = super(HomeView, self).get_context_data(**kwargs)

        user = self.request.user
        followees = FollowRelation.objects.filter(follower=user).values_list('followee__id', flat=True)
        lookup_user_ids = [user.id] + list(followees)
        context['contents'] = Content.objects.select_related('user').prefetch_related('image_set').filter(
            user__id__in=lookup_user_ids
        )

        return context

def get_context_data를 오버라이딩 할 때 super를 써주는 이유는 super를 통해 기존에 구현되어 있던 get_context_data을 가지고 온다는 것이다.

def get_context_data 에서도 상속과정에서 부모에 정의된 def get_context_data를 모두 실행하기 위해 저렇게 실행한 것이다.

일반적으로 get_context_data 는 모든 상위 클래스의 컨텍스트 데이터를 현재 클래스의 컨텍스트 데이터와 병합한다. 컨텍스트를 변경하려는 클래스에서 이 동작을 유지하려면 수퍼 클래스에서 get_context_data 를 호출해야한다.

profile
Sometimes you gotta run before you can walk.

0개의 댓글