[DRF] - mixins

์˜ค๋™ํ›ˆยท2022๋…„ 8์›” 18์ผ
0

Django

๋ชฉ๋ก ๋ณด๊ธฐ
8/24

1. mixins

๋ฏน์Šค์ธ์ด๋ž€ ํŠน์ •ํ•œ ํด๋ž˜์Šค์— ์ƒ์†์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์†์„ฑ์ด๋‚˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€(Mix in)ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์ž˜ ํ™œ์šฉํ•œ ์˜คํ”ˆ์†Œ์Šค๊ฐ€ ๋ฐ”๋กœ Django Rest Framework์ด๋‹ค. Django Rest Framework์—์„œ๋Š” GenericAPIView์— ์ƒ์„ฑ, ์ˆ˜์ • ๋“ฑ์˜ ๋‹ค์–‘ํ•œ ๋ฏน์Šค์ธ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด ์‰ฝ๊ฒŒ API View๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

Django Rest Framework ๊ณต์‹๋ฌธ์„œ์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ด๋ณด๋ฉด ListModelMixin๊ณผ CreateModelMixin์„ ์ƒ์† ๋ฐ›์Œ์œผ๋กœ์จ get ๋ฉ”์†Œ๋“œ์™€ post ๋ฉ”์†Œ๋“œ์—์„œ list์™€ create๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋“ค์€ ๋ณธ์ธ๋“ค์ด ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋ณด๋‹ค ์‰ฝ๊ณ  ๊ฐ„ํŽธํ•˜๊ฒŒ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“ƒ rest_framework/mixins.py

์•„๋ž˜์˜ Class๋“ค์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด import๋ฅผ ํ•„์š”๋กœ ํ•ฉ๋‹ˆ๋‹ค.

from rest_framework.mixins import (
    ListModelMixin, CreateModelMixin, UpdateModelMixin)

๐Ÿ“ƒ rest_framework/viewsets.py
์•„๋‹ˆ๋ฉด viewsets ํŒŒ์ผ ๋‚ด ViewSet ์ข…๋ฅ˜๋“ค ์ค‘ ์›ํ•˜๋Š” ํ˜•ํƒœ๋ฅผ importํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

from rest_framework.viewsets import ModelViewSet

1. .ListModelMixin

์ฟผ๋ฆฌ ์ง‘ํ•ฉ ๋‚˜์—ด

method : GET

์ฃผ๋กœ ์“ฐ๋Š” ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

def list(request, *args, **kwargs)

์œ„์˜ ์ฝ”๋“œ๋งŒ์œผ๋กœ View๊ฐ€ ๋งŒ๋“ค์–ด์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ Django์—์„œ ์ œ๊ณตํ•˜๋Š” ListAPIView๋ฅผ ์ƒ์†๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋Ÿผ ์ด ๊ฐ„๋‹จํ•œ ํ˜•ํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š”์ง€ ํ•œ ๋ฒˆ ์‚ดํŽด๋ด๋ณด์ž.

๐Ÿ“ƒ rest_framework/generics.py

class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    """
    Concrete view for listing a queryset.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

์ด ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํžˆ ์š”์•ฝํ•˜๋ฉด, ์‚ฌ์šฉ์ž๊ฐ€ GET ์š”์ฒญ์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, list()๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค๋Š” ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด list() ํ•จ์ˆ˜๋Š” ์–ด๋”จ๋Š”์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋ ค๋ฉด restframework/mixins.py์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ListModelMixin class์ž…๋‹ˆ๋‹ค.

๐Ÿ“ƒ rest_framework/mixins.py

class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())	# 1๋ฒˆ

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)	# 2๋ฒˆ
        return Response(serializer.data)						# 3๋ฒˆ

๋จผ์ € ํ•œ ์ค„์”ฉ ์‚ดํŽด๋ด๋ณด์ž. ๋จผ์ € 1๋ฒˆ์„ ์‚ดํŽด๋ณด๋ฉด

๐Ÿ“ƒ 1๋ฒˆ

queryset = self.filter_queryset(self.get_queryset())

filter_queryset๊ณผ get_queryset์€ ํ•จ์ˆ˜๋ช…์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด queryset์„ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด query๋Š” ์–ด๋””์„œ ๊ฐ€์ ธ์˜ค๋Š”๊ฑธ๊นŒ?

๐Ÿ“ƒ view.py

class DongListView(ListAPI):
    serializer_class = DongSerializer
    queryset = Dong.objects.all()

ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  queryset = model.objects.all()์™€ ๊ฐ™์ด ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด ๋ฐฉ๊ธˆ ๋ณธ 1๋ฒˆ์˜ ์ฝ”๋“œ๊ฐ€ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๐Ÿ“ƒ 2๋ฒˆ

serializer = self.get_serializer(queryset, many=True)

์—ฌ๊ธฐ ์—ญ์‹œ ์•Œ์ง€ ๋ชปํ•˜๋Š” ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์ด ๋ณ€์ˆ˜์— ๋„˜๊ฒจ์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

get_serializer์˜ ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด serializer๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด ๋˜ํ•œ DongListView์—์„œ ์„ ์–ธํ•œ serializer_class์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ๋‹ค๋ฅธ ์ ์ด ์žˆ๋Š”๋ฐ, ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ๋„ฃ์–ด์ค€๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ queryset๊ณผ many=True ๊ฐ’์ด ๋“ค์–ด๊ฐ€์žˆ๋Š”๋ฐ, queryset์€ Model์˜ ๋ฐ์ดํ„ฐ๋“ค์ธ ๋ฐ˜๋ฉด์— many=True๋Š” ์–ด๋–ค ๊ฐ’์„ ์˜๋ฏธํ• ๊นŒ์š”?

๋ฐ”๋กœ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ช…์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ์—ฌ๊ฑฐ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋“ค์„ ์ง๋ ฌํ™”ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. iterableํ•œ ๊ฐ์ฒด(list, dict, set...)๋“ค์„ ์ง๋ ฌํ™”ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๐Ÿ“ƒ 3๋ฒˆ

return Response(serializer.data)

๋งˆ์ง€๋ง‰ ์ค„์ž…๋‹ˆ๋‹ค! Response๋ผ๋Š” ํ•จ์ˆ˜์— serializre์˜ data๋ฅผ ๋„˜๊ฒจ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์š”์ฒญ(request)๊ณผ ์‘๋‹ต(response) ์ค‘, ์„œ๋ฒ„๋Š” Request๋ฅผ ๋ฐ›์•˜์œผ๋ฏ€๋กœ Response๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋„˜๊ฒจ์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๋Š” Post๋“ค์˜ ๋ชฉ๋ก์„ Response๋กœ ๋ฐ›๊ธฐ๋ฅผ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, serializer๋ฅผ ํ†ตํ•ด JSON ํ˜•ํƒœ๋กœ ๋ฐ”๋€ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ง€๊ธˆ๊นŒ์ง€ ์•Œ์•„๋ณธ ๊ฒƒ์„ ์ •๋ฆฌํ•ด๋ณด์ž!

  1. ์‚ฌ์šฉ์ž๊ฐ€ URL์— GET์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค.
  2. URL์— ๋ผ์šฐํŒ…๋˜์–ด ์‹คํ–‰ํ•˜๊ธฐ๋กœ ์•ฝ์†ํ•œ View๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  3. View์— ์„ ์–ธํ•œ queryset์ด list()์— ๋„˜๊ฒจ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  4. ๋„˜๊ฒจ์ง„ query์€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ View์—์„œ ์„ ์–ธํ•œ serializer๋ฅผ ํ†ตํ•ด JSON ํ˜•ํƒœ๋กœ ๋ฐ”๋€Œ๊ฒŒ๋ฉ๋‹ˆ๋‹ค.
  5. JSON์œผ๋กœ ๋ฐ”๋€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์‘๋‹ต(Response)ํ•ฉ๋‹ˆ๋‹ค.

2. .CreateModelMixin

์ƒˆ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐ ์ €์žฅ

method : POST

์ฃผ๋กœ ์“ฐ๋Š” ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

def create(request, *args, **kwargs)

๋™์ผํ•˜๊ฒŒ ์œ„์˜ ์ฝ”๋“œ๋งŒ์œผ๋กœ View๊ฐ€ ๋งŒ๋“ค์–ด์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ CreateAPIView๋ฅผ ์ƒ์†๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด์ž.

๐Ÿ“ƒ rest_framework/generics.py

class CreateAPIView(mixins.CreateModelMixin,
                    GenericAPIView):
    """
    Concrete view for creating a model instance.
    """
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

์‚ฌ์šฉ์ž๊ฐ€ POST ์š”์ฒญ์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, create()๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค๋Š” ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด create() ํ•จ์ˆ˜๋Š” ์–ด๋”จ๋Š”์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋ ค๋ฉด restframework/mixins.py์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” CreateModelMixin Class๋ฅผ ์‚ดํŽด๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ restframework์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” CreateModelMixin class์ž…๋‹ˆ๋‹ค.

class CreateModelMixin:
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)			# 1๋ฒˆ
        serializer.is_valid(raise_exception=True)					# 2๋ฒˆ
        self.perform_create(serializer)								# 3๋ฒˆ
        headers = self.get_success_headers(serializer.data)			# 4๋ฒˆ
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) # 5๋ฒˆ

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}
            

๋จผ์ € ํ•œ ์ค„์”ฉ ์‚ดํŽด๋ด๋ณด์ž. ๋จผ์ € 1๋ฒˆ์„ ์‚ดํŽด๋ณด๋ฉด

๐Ÿ“ƒ 1๋ฒˆ

serializer = self.get_serializer(data=request.data)

get_serializer์˜ ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด serializer๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด ๋˜ํ•œ DongListView์—์„œ ์„ ์–ธํ•œ serializer_class์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ƒ 2๋ฒˆ

serializer.is_valid(raise_exception=True)

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๐Ÿ“ƒ 3๋ฒˆ

self.perform_create(serializer)

serializer๋ฅผ ์ €์žฅํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

๐Ÿ“ƒ 4๋ฒˆ

headers = self.get_success_headers(serializer.data)

์„ฑ๊ณตํ–ˆ์„ ๋•Œ ์‘๋‹ต ํ•ด์ค„ ํ—ค๋” ๋ชฉ๋ก์„ ํ—ค๋”์— ๋„ฃ์–ด์ฃผ๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

๐Ÿ“ƒ 5๋ฒˆ

return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

์œ„์˜ ๊ณผ์ •์ด ์›ํ™œํ•˜๊ฒŒ ์ž˜ ์ง„ํ–‰๋˜์—ˆ๋‹ค๋ฉด ์‘๋‹ตํ•ด์ฃผ๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

3. .RetrieveModelMixin

๊ธฐ์กด ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜์„ ๊ตฌํ˜„

method : GET

์ฃผ๋กœ ์“ฐ๋Š” ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

def retrieve(request, *args, **kwargs)

์œ„์˜ ์ฝ”๋“œ๋งŒ์œผ๋กœ View๊ฐ€ ๋งŒ๋“ค์–ด์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ Django์—์„œ ์ œ๊ณตํ•˜๋Š” RetrieveAPIView๋ฅผ ์ƒ์†๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋Ÿผ ์ด ๊ฐ„๋‹จํ•œ ํ˜•ํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์„๊นŒ?

๐Ÿ“ƒ rest_framework/generics.py

class RetrieveAPIView(mixins.RetrieveModelMixin,
                      GenericAPIView):
    """
    Concrete view for retrieving a model instance.
    """
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

์‚ฌ์šฉ์ž๊ฐ€ GET ์š”์ฒญ์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, retrieve()๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค๋Š” ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด retrieve() ํ•จ์ˆ˜๋Š” ์–ด๋”จ๋Š”์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋ ค๋ฉด ์•„๋ž˜๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ restframework์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” RetrieveModelMixin class์ž…๋‹ˆ๋‹ค.

class RetrieveModelMixin:
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()				# 1๋ฒˆ
        serializer = self.get_serializer(instance)	# 2๋ฒˆ
        return Response(serializer.data)			# 3๋ฒˆ
        
        
# get_object ์†Œ์Šค ์ฝ”๋“œ
def get_object(self, queryset=None):
        """
        Returns the object the view is displaying.

        By default this requires `self.queryset` and a `pk` or `slug` argument
        in the URLconf, but subclasses can override this to return any object.
        """
        # Use a custom queryset if provided; this is required for subclasses
        # like DateDetailView
        if queryset is None:
            queryset = self.get_queryset()

        # Next, try looking up by primary key.
        pk = self.kwargs.get(self.pk_url_kwarg, None)
        slug = self.kwargs.get(self.slug_url_kwarg, None)
        if pk is not None:
            queryset = queryset.filter(pk=pk)

        # Next, try looking up by slug.
        if slug is not None and (pk is None or self.query_pk_and_slug):
            slug_field = self.get_slug_field()
            queryset = queryset.filter(**{slug_field: slug})

        # If none of those are defined, it's an error.
        if pk is None and slug is None:
            raise AttributeError("Generic detail view %s must be called with "
                                 "either an object pk or a slug."
                                 % self.__class__.__name__)

        try:
            # Get the single item from the filtered queryset
            obj = queryset.get()
        except queryset.model.DoesNotExist:
            raise Http404(_("No %(verbose_name)s found matching the query") %
                          {'verbose_name': queryset.model._meta.verbose_name})
        return obj   # Model.object.get(pk=pk) ์˜๋ฏธ

๐Ÿ“ƒ 1๋ฒˆ

instance = self.get_object()

์œ„์— get_object ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ฒจ๋ถ€ํ–ˆ๋Š”๋ฐ ์ด๋ฅผ ์ •๋ฆฌํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

get_object๋Š”

  • queryset๊ณผ pk๊ฐ’์„ ์ธ์ž๋กœ ๋ฐ›์•„์„œ,
  • queryset.filter(pk=pk)๋กœ queryset์„ ๋ฝ‘๊ณ ,
  • obj = queryset.get()์œผ๋กœ ๊ฐ์ฒด๋งŒ ๋ฝ‘์•„์„œ ๋ฆฌํ„ดํ•ด ์ฃผ๋Š” ๋ฉ”์†Œ๋“œ
    => ๊ฒฐ๊ตญ, ์œ„ ์ฝ”๋“œ๋Š” Model.objects.get(pk=pk) ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ 1๋ฒˆ์€ Model.objects.get(pk=pk)์„ instance๋ผ๋Š” ๋ณ€์ˆ˜์— ๋‹ด์•„์ฃผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ƒ 2๋ฒˆ
get_serializer๋Š” instance๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„์„œ, ํ•ด๋‹น ๊ฐ์ฒด์„ serializeํ•ด ์ฃผ๋Š” ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค.

๐Ÿ“ƒ 3๋ฒˆ
serializer.data๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4. .UpdateModelMixin

๊ธฐ์กด ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค ์—…๋ฐ์ดํŠธ ๋ฐ ์ €์žฅ ๊ตฌํ˜„

method : PUT

์ฃผ๋กœ ์“ฐ๋Š” ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

def update(request, *args, **kwargs)

๊ทธ๋Ÿผ ์ด ๊ฐ„๋‹จํ•œ ํ˜•ํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์„๊นŒ?

class UpdateAPIView(mixins.UpdateModelMixin,
                    GenericAPIView):
    """
    Concrete view for updating a model instance.
    """
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)

์‚ฌ์šฉ์ž๊ฐ€ PUT ์š”์ฒญ์„ ๋ณด๋‚ผ ์‹œ, update() ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ , patch ์š”์ฒญ์„ ๋ณด๋‚ผ ์‹œ partial_update() ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ restframework์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” UpdateModelMixin class์ž…๋‹ˆ๋‹ค.

class UpdateModelMixin:
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)				# 1๋ฒˆ
        instance = self.get_object()						# 2๋ฒˆ
        serializer = self.get_serializer(instance, data=request.data, partial=partial) # 3๋ฒˆ
        serializer.is_valid(raise_exception=True)			# 4๋ฒˆ
        self.perform_update(serializer)						# 5๋ฒˆ

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

๐Ÿ“ƒ 1๋ฒˆ
pop ๋ฉ”์†Œ๋“œ๋กœ ๋”•์…”๋„ˆ๋ฆฌ ๋‚ด์— partial ๋ผ๋Š” ํ‚ค์›Œ๋“œ ์ธ์ˆ˜๋ฅผ ๊บผ๋‚ด์ค๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์—†๋‹ค๋ฉด ๋ฉ”์†Œ๋“œ์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ง€์ •ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“ƒ 2๋ฒˆ
Model.objects.get(pk=pk)์„ instance๋ผ๋Š” ๋ณ€์ˆ˜์— ๋‹ด์•„์ฃผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ƒ 3๋ฒˆ
get_serializer๋Š” instance๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„์„œ, ํ•ด๋‹น ๊ฐ์ฒด์„ serializeํ•ด ์ฃผ๋Š” ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค.

๐Ÿ“ƒ 4๋ฒˆ
์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๐Ÿ“ƒ 5๋ฒˆ
์•„๋ž˜ perform_update ํ•จ์ˆ˜๊ฐ€ ๋ณ„๋„๋กœ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ํ•จ์ˆ˜๋Š” serializer์˜ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค.

5. .DestoryModelMixin

๊ธฐ์กด ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค์˜ ์‚ญ์ œ ๊ตฌํ˜„

method : DELETE

์ฃผ๋กœ ์“ฐ๋Š” ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

def destory(request, *args, **kwargs)

๊ทธ๋Ÿผ ์ด ๊ฐ„๋‹จํ•œ ํ˜•ํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์„๊นŒ?

class DestroyAPIView(mixins.DestroyModelMixin,
                     GenericAPIView):
    """
    Concrete view for deleting a model instance.
    """
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

์‚ฌ์šฉ์ž๊ฐ€ delete ์š”์ฒญ์„ ๋ณด๋‚ผ ์‹œ, destory() ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ restframework์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” DestoryModelMixin class์ž…๋‹ˆ๋‹ค.

class DestroyModelMixin:
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()						# 1๋ฒˆ
        self.perform_destroy(instance)						# 2๋ฒˆ
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

๐Ÿ“ƒ 1๋ฒˆ
Model.objects.get(pk=pk)์„ instance๋ผ๋Š” ๋ณ€์ˆ˜์— ๋‹ด์•„์ฃผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ƒ 2๋ฒˆ
Class ๋‚ด์— perform_destroy๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. instance์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ์ง€์›Œ์ฃผ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

2. generics

๐Ÿ“ƒ rest_framework/generics.py

์•„๋ž˜์˜ Class๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด import๋ฅผ ํ•„์š”๋กœ ํ•ฉ๋‹ˆ๋‹ค.

from rest_framework.mixins import (
    ListModelMixin, CreateModelMixin, UpdateModelMixin)

1. get_queryset

get_queryset์€ ๋‹ค์Œ ํŠน์ง•๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๋‹ค๋ฅธ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด self.get_queryset์„ ์ด์šฉํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  3. queryset์€ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๊ณ  ํ›„์† ์š”์ฒญ๋“ค์— ๋Œ€ํ•ด์„œ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ์บ์‹ฑ๋ฉ๋‹ˆ๋‹ค.

!!์—ฌ๊ธฐ์„œ ์บ์‹ฑ๋œ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ์ž˜ ์ดํ•ด ๋ชปํ–ˆ๊ณ  ์ข€ ๋” ๋“ค์—ฌ๋‹ค ๋ณผ ํ•„์š”๊ฐ€ ์žˆ์–ด๋ณด์ž„
์–ด๋–ค์‹์œผ๋กœ ์บ์‹ฑ๋˜๊ณ  ์–ด๋–ค ๋ถ€๋ถ„์—์„œ ํšจ๊ณผ์ ์ธ์ง€ check ํ•„์š”!!

๊ทธ๋Ÿผ queryset๊ณผ get_queryset()์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡์ผ๊นŒ? ์š”์•ฝํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

queryset์€ request ๋ฐœ์ƒ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์ฟผ๋ฆฌ์…‹์ด ๋™์ž‘ํ•˜๊ณ , get_queryset()์€ ๋งค request๋งˆ๋‹ค ์ฟผ๋ฆฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ์กฐ๊ฑด์ด ๊ฑธ๋ฆฐ ์ฟผ๋ฆฌ์…‹์„ ์“ธ ๋•Œ๋Š” get_queryset()์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์ž.

generics APIView ์ •๋ฆฌ (GenericsAPIView ์ƒ์†)

  • generics.CreateAPIView : post โ†’ create
  • generics.ListAPIView : get โ†’ list
  • generics.RetrieveAPIView : get โ†’ retrieve
  • generics.DestroyAPIView : delete โ†’ destroy
  • generics.UpdateAPIView : put โ†’ update, patch โ†’ partial_update
  • generics.ListCreateAPIView : get โ†’ list, post โ†’ create
  • generics.RetrieveUpdateAPIView : get โ†’ retrieve, put โ†’ update, patch โ†’ partial_update
  • generics.RetrieveDestroyAPIView : get โ†’ retrieve, delete โ†’ destroy
  • generics.RetrieveUpdateDestroyAPIView : get โ†’ retrieve, put โ†’ update, patch โ†’ partial_update, delete โ†’ destroy

View ๊ตฌํ˜„ ์‹œ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค์˜ ์ถ”์ƒํ™” ์ •๋„: APIView < mixins < Generics < ViewSet

  • mixins : APIView์—์„œ ์ผ๋ฐ˜์ ์ธ ๋กœ์ง๋“ค์„ ์„ž์–ด์„œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ธ ๊ฒƒ
  • Generics : mixins ์‚ฌ์šฉ์„ ํŒจํ„ดํ™”ํ•ด์„œ ์ •๋ฆฌํ•จ
  • ViewSet : Generics๋ฅผ ํ•œ๋ฒˆ ๋” ํ•ฉ์ณ์„œ ์ •๋ฆฌ

์ด๋ฅผ ์–ด๋–ป๊ฒŒ view์—์„œ ์—ฐ๋™ํ•ด ์‚ฌ์šฉํ•˜๋Š”์ง€๋„ ์ถ”๊ฐ€

profile
์‚ฝ์งˆ์˜ ๊ธฐ๋ก๋“ค๐Ÿฅ

0๊ฐœ์˜ ๋Œ“๊ธ€