Настройте Django Rest Framework на заполнение поля user пользователем, вошедшим в систему, перед проверкой сериализатора
У меня есть конечная точка API, поддерживающая метод POST, который работает, если я включаю user
в полезную нагрузку запроса.
Я хотел бы исключить это из полезной нагрузки запроса и заставить DRF просто использовать зарегистрированного пользователя.
Я получаю следующую ошибку, когда опускаю user
из тела запроса:
HTTP 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"user": [
"This field is required."
]
}
Похоже, что это происходит, когда фреймворк вызывает serializer.is_valid()
.
Как настроить DRF на заполнение пользователя из request.user
, чтобы проверка сериализатора не завершилась неудачей?
models.py
class Task(models.Model):
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
domain = models.CharField(max_length=settings.MAX_CHAR_COUNT)
сериализаторы
class TaskSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.SlugRelatedField(queryset=CustomUser.objects.all(), slug_field='email')
class Meta:
model = Task
fields = ['id', 'created', 'domain', 'user']
views.py
class TaskApiViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated,]
serializer_class = TaskSerializer
task_service = TaskService()
"""
GET /api/tasks
"""
def get_queryset(self):
user = self.request.user
if user.is_superuser:
return Task.objects.all()
return Task.objects.filter(user=self.request.user)
"""
POST /api/tasks
"""
def create(self, request):
domain = request.data['domain']
can_create_task = self.task_service.can_create_task(user=request.user, domain_name=domain)
if not can_create_task:
raise PermissionDenied(code=None, detail=None)
return super().create(request)
Возможно, вам придется полностью переопределить метод ViewSet
вашего create()
, чтобы иметь возможность передать измененный dict
в сериализатор. Вы можете просто скопировать исходное определение
После этого вы можете добавить пользователя в данные запроса, сделав копию, изменив ее и передав сериализатору:
def create(self, request, *args, **kwargs):
user_id = self.request.user.id
domain = request.data['domain']
new_data = request.data.copy()
new_data.update({"user": user_id})
can_create_task = self.task_service.can_create_task(user=request.user, domain_name=domain)
if not can_create_task:
raise PermissionDenied(code=None, detail=None)
# original definition of create() with new_data
serializer = self.get_serializer(data=new_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)
Правильный способ сделать это, согласно Django Rest Framework, заключается в переопределении метода perform_create()
в вашем ViewSet, который отвечает за создание экземпляра модели с помощью сериализатора. Вы можете передать сериализатору дополнительные данные:
def perform_create(self, serializer):
serializer.save(user=self.request.user)
Оригинальное определение метода perform_create()
можно найти здесь.
Простым решением вашей проблемы будет использование поля "extra_kwargs" внутри вашего класса Meta, для вашего случая это будет что-то вроде этого:
class Meta:
model = Task
fields = ['id', 'created', 'domain']
extra_kwargs = {'user': {'default': serializers.CurrentUserDefault()}}