Django Views.py: kwargs и сериализатор без явной ссылки в определении класса
Я изучаю учебник по Django Rest Framework ( исходный код здесь) и у меня есть несколько вопросов по поводу следующего фрагмента кода:
class ReviewCreate(generics.CreateAPIView):
serializer_class = ReviewSerializer
permission_classes = [IsAuthenticated]
throttle_classes = [ReviewCreateThrottle]
def get_queryset(self):
return Review.objects.all()
def perform_create(self, serializer):
pk = self.kwargs.get('pk')
watchlist = WatchList.objects.get(pk=pk)
review_user = self.request.user
review_queryset = Review.objects.filter(watchlist=watchlist, review_user=review_user)
if review_queryset.exists():
raise ValidationError("You have already reviewed this movie!")
if watchlist.number_rating == 0:
watchlist.avg_rating = serializer.validated_data['rating']
else:
watchlist.avg_rating = (watchlist.avg_rating + serializer.validated_data['rating'])/2
watchlist.number_rating = watchlist.number_rating + 1
watchlist.save()
serializer.save(watchlist=watchlist, review_user=review_user)
- In the class definition, the variable
serializer_classis declared; however in theperform_createmethod,serializeris an argument. Given the differences in naming, how are these two related? - In the method
perform_create,self.kwargsis referenced. However, I don't see a kwargs argument passed to any__init__method or else attached to the class object. How/where is kwargs passed to the class?
В обоих случаях я могу только предположить, что унаследованный класс (generics.CreateAPIView) имеет метод __init__, который присваивает переменную serializer_class переменной serializer. Как он "слушает" определение дочернего класса serializer_class, я понятия не имею. А что касается kwargs, я не понимаю, как это передается дочернему классу без явного вызова определения в аргументах.
Edit, этот вопрос Kwargs в Django не отвечает на мой вопрос - он просто объясняет, что такое аргументы ключевых слов. Меня не смущает их название, меня смущает их невидимая, но неявная ссылка в этом коде.
Отвечая на ваш первый вопрос, мы должны отметить две вещи:
Сначала метод
perform_createиспользуется в методеcreate, связанном сCreateModelMixin(см. https://github.com/encode/django-rest-framework/blob/71e6c30034a1dd35a39ca74f86c371713e762c79/rest_framework/mixins.py#L16). КлассCreateAPIViewнаследует от этого миксина, а также отGenericAPIView(см. https://github.com/encode/django-rest-framework/blob/b1004a47334a0dd1929e6d50b8f7ff6badc959f4/rest_framework/generics.py#L184). Как видите, упомянутый выше методcreateиспользует метод классаperform_createи нуждается в сериализаторе. Определениеperform_createбез этого аргумента привело бы к ошибке при создании объектов этим методом.Еще один момент, который следует отметить, заключается в том, что используемый сериализатор берется из метода
get_serializer. Проверив исходный код дляGenericAPIView(https://github.com/encode/django-rest-framework/blob/b1004a47334a0dd1929e6d50b8f7ff6badc959f4/rest_framework/generics.py#L103), можно увидеть, что этот метод вызываетget_serializer_class, который извлекает сериализатор, определенныйserializer_class.
В заключение, если вы больше ничего не измените, serializer, который будет передан в качестве параметра, будет экземпляром вашего класса сериализатора, определенного в serializer_class.
Переходя ко второму пункту, если вы попытаетесь найти родительский класс GenericAPIView и продолжить поиск базового класса, от которого наследуются эти классы, вы обнаружите, что базовым классом является View от django.views.generic. Там вы найдете в методе setup (https://github.com/django/django/blob/27aa7035f57f0db30b6632e4274e18b430906799/django/views/generic/base.py#L124), где инициализируется атрибут kwargs. Также вы можете увидеть в кодовой документации этого метода следующее утверждение:
"""Initialize attributes shared by all view methods."""
Таким образом, в любом создаваемом нами представлении (если оно имеет View в качестве базового класса) мы всегда сможем манипулировать self.request, self.args и self.kwargs. Надеюсь, я понятно объяснил!