class CustomerSerializer(serializers.ModelSerializer):
team = serializers.StringRelatedField(read_only=True)
country = serializers.PrimaryKeyRelatedField(queryset=Country.objects.all())
class Meta:
model = Customer
fields = "__all__"
class CustomerDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
permission_classes = [IsAuthenticated]
- DetailAPIView인데 왜 queryset은 Customer.objects.all()인가?
- 코드는 아주 심플한테, 어떻게 이 3줄의 코드가 detail, update, delete 기능을 수행하는가?
==> 위의 코드가 어떻게 작동하는지 이해할려면, get_object 메소드의 역할에 대한 이해가 중요함
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
"""
Concrete view for retrieving, updating or deleting a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
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)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
get_object는
- queryset과 pk값을 인자로 받아서,
- queryset.filter(pk=pk)로 queryset을 뽑고,
- obj = queryset.get()으로 객체만 뽑아서 리턴해 주는 메소드임
=> 결국, 위 코드는 Customer.objects.get(pk=pk) 리턴함
get_serializer는
- instance을 인자로 받아서, 해당 객체을 serialize해 주는 메소드임
# RetrieveModelMixin 소스 코드
class RetrieveModelMixin:
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object() # Customer.objects.get(pk=pk)를 의미
serializer = self.get_serializer(instance)
return Response(serializer.data)
# 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 # Customer.object.get(pk=pk) 의미
# get_serializer 소스 코드
def get_serializer(self, instance=None, data=None,
files=None, partial=False):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
return serializer_class(instance, data=data, files=files,
partial=partial, context=context)
from contacts.models import *
> queryset = Customer.objects.all()
> guery = queryset.filter(id=7)
<QuerySet [<Customer: Tecnituberias>]>
> obj = guery.get()
> obj
<Customer: Tecnituberias>
소스코드를 보기 전에 Django REST 공식문서 사례를 통해서 아래 내용을 먼저 숙지할 필요가 있다.
class UpdateModelMixin:
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
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)
- get_queryset은 왜 override하여 작성하였는가?
=> Customer.objects.filter(team=team)으로 해야 하기 때문임. 만약, all() 혹은 filter(pk=pk)였다면 굳이 override할 필요가 없음- serialzer.py에서는 create를 왜 override하여 작성하였는가?
=> DB에 저장해야 될 모델이 Board뿐만 아니라 BoardAccess도 있기 때문에 둘을 동시에 같이 저장하기 위해서 create을 override하여 작성함- perform_create는 왜 overried하여 작성하였는가?
=> request로 전달된 데이터 외에 팀 정보도 추가해서 저장해야 하기 때문에 override하여, serializer.save(team=team)으로 저장을 함
class CustomerListCreateAPIView(generics.ListCreateAPIView):
serializer_class = CustomerSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
team = self.request.user.profile.team
queryset = Customer.objects.select_related('team').filter(team=team)
return queryset
def perform_create(self, serializer):
team = self.request.user.profile.team
serializer.save(team=team)
2-1) CreateModelMixin 이해하기
[create 메소드 구동 플로우]
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
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 {}
2-2) ListModelMixin 이해하기
queryset = self.filter_queryset(self.get_queryset()) 이 부분이 잘 이해가 안 됨??
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
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)
return Response(serializer.data)
filter_queryset는 필터 처리하는 부분이에요.
generics.py에 보면 filter_queryset 함수 있습니다.
drf에서 자동으로 필터 처리 해주는 함수라고 생각하시면될것 같아요.
기본 필터 처리 함수요~