Валидация Django Rest Framework в методе POST APIView - PullRequest
0 голосов
/ 27 июня 2018

Я новичок в DRF и пытаюсь построить остальные API, мне нужно сделать API для выполнения задач, а не только для CRUD, поэтому я переопределил метод POST APIView как:

class DeploymentsList(viewsets.ModelViewSet):
    queryset = DeploymentOnUserModel.objects.all()
    serializer_class = DeploymentonUserSerializer

    def create(self, request, *args, **kwargs):
        """overwrite this for extra actions"""
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid(raise_exception=True):
            print('valid request')
            serializer.save()
            return Response(serializer.data)
        else:
            print('Something invalid')
            return Response('Invalid request')

models.py:

    services = (
    ('Single', 'Single'),
    ('Multiple', 'Multiple'),
)


class DeploymentOnUserModel(models.Model):
    deployment_name = models.CharField(max_length=256, )
    credentials = models.TextField(blank=False)
    project_name = models.CharField(max_length=150, blank=False)
    project_id = models.CharField(max_length=150, blank=True)
    cluster_name = models.CharField(max_length=256, blank=False)
    zone_region = models.CharField(max_length=150, blank=False)
    services = models.CharField(max_length=150, choices=services)
    configuration = models.TextField()
    routing = models.TextField()

    def save(self, **kwargs):
        if not self.id and self.services == 'Multiple' and not self.routing and not self.configuration:
            raise ValidationError("You must have to provide routing for multiple services deployment.")
        super().save(**kwargs)

serializers.py:

class DeploymentonUserSerializer(serializers.ModelSerializer):
    model = DeploymentOnUserModel
    fields = '__all__'
    readonly_fields = 'pk'

urls.py:

app_name = 'deployments'

urlpatterns = [
    path('deployments/', apiview.DeploymentsList.as_view({'get': 'list', 'post': 'create'}), name='deployment_list'),
    path('deployments/<int:pk>', apiview.DeploymentDetail.as_view(), name='deployment_detail')

]

Ошибка возвращается:

AttributeError: у объекта 'str' нет атрибута 'values'

Обновление: Полная трассировка

Internal Server Error: /api/v1/deployments/
Traceback (most recent call last):
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
    response = get_response(request)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/viewsets.py", line 95, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/views.py", line 494, in dispatch
    response = self.handle_exception(exc)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/views.py", line 454, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/views.py", line 491, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/abdul/PycharmProjects/KontainerApi/deployments/apiview.py", line 15, in create
    serializer.is_valid(raise_exception=False)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 236, in is_valid
    self._validated_data = self.run_validation(self.initial_data)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 435, in run_validation
    value = self.to_internal_value(data)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 459, in to_internal_value
    fields = self._writable_fields
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/utils/functional.py", line 36, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 370, in _writable_fields
    field for field in self.fields.values()
AttributeError: 'str' object has no attribute 'values'
[27/Jun/2018 16:11:41] "POST /api/v1/deployments/ HTTP/1.1" 500 15073

Но я не знаю, как я могу проверить запрос? когда я переопределяю метод POST APIView.

Почтовые данные:

  {
"deployment_name": "dep5",
"credentials": "cre4",
"project_name": "pro4",
"project_id": "004",
"cluster_name": "clus4",
"zone_region": "zon4",
"services": "Single",
"configuration": "conf4",
"routing": "route4"

}

Ответы [ 3 ]

0 голосов
/ 27 июня 2018

Не очень понятно, чего вы хотите достичь.

Я бы сказал, что вы хотите выполнить другое задание после получения запроса и после проверки входных данных.

Хотя не уверен, какую задачу вы хотите выполнить и когда - до или после сохранения вашей модели.

но вы можете сделать это как часть создания до создания вашей модели:

 def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)

     **.... your task - access to data via serializer.validated_data....**

    self.perform_create(serializer)        
    return Response(serializer.data)

или, если вы хотите выполнить что-то после создания вашей модели, вы можете переопределить execute_create (как мы видим из реализации метода create, он вызывается сразу после проверки ввода)

def perform_create(self, serializer):
    instance =  serializer.save()
     .... your task ....

Обновлено для устранения проблемы «AttributeError: у объекта 'str' нет атрибута 'values'"

Проблема в том, что вы используете viewset - Viewset предоставляет вам «представление управления ресурсами», которое вы можете использовать для просмотра, загрузки, обновления, удаления ресурса.

Вам не нужно явно регистрировать представления в urlconf для list / create, а затем подробно.

Вместо этого сделайте это с классом маршрутизатора, и он даст вам все представления (включая детали):

router = DefaultRouter()
router.register(r'deployment', DeploymentsList, base_name='deployment')
urlpatterns = router.urls

и теперь вы можете сделать:

  • GET развертывание /
  • Развертывание POST
  • GET deploy / {id} -> detail

Другая проблема, с которой вы столкнулись, связана с проверкой. Я не рекомендую поднимать ValidationError в функции сохранения модели.

Существует сериализатор для обработки вашей проверки, и вы можете сделать это в функции проверки в вашем DeploymentUserSerializer

def validate(self, attrs):
    # perform your validation here
    return attrs
0 голосов
/ 27 июня 2018

Попробуйте этот фрагмент,

def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    if serializer.is_valid():
        execute_my_task(serializer.data)
        # you will get serialized data in 'serializer.data'
        # 'execute_my_task()' is the task function
        return Response(data="task success")
    else:
        return Response(serializer.errors)  # this will show the error during the validation process



Оператор if serializer.is_valid(raise_exception=True): не возвращает значений bool, если raise_exception=True.

См. Этот документ DRF для is_valid()

0 голосов
/ 27 июня 2018

Вы можете использовать ListCreateAPIView, как показано ниже. Мы также можем напрямую использовать ListCreateAPIView в urls.py.

serializers.py

from rest_framework import serializers
from .models import DeploymentOnUserModel

class DeploymentOnUserModelSerializer(serializers.ModelSerializer)
    class Meta:
        model = DeploymentOnUserModel
        fields = [
            'deployment_name', 'credentials', 'project_name', 
            'project_id', 'cluster_name', 'zone_region', 'services',
            'configuration', 'routing']

views.py

from rest_framework.generics import ListCreateAPIView
from .models import DeploymentOnUserModel
from .serializers import DeploymentOnUserModelSerializer 

class DeploymentsList(ListCreateAPIView):
     queryset = DeploymentOnUserModel.objects.all()
     serializer_class = DeploymentOnUserModelSerializer

Ваш ответ Исправить ошибку

def create(self, request, *args, **kwargs):
    """overwrite this for extra actions"""
    serializer = self.serializer_class(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(serializer.data)

Ссылка: https://github.com/encode/django-rest-framework/blob/master/rest_framework/generics.py

...