сериализаторы django rest m2m выдают ошибку Bad request - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть две модели: Задача и Сценарий:

class Task(models.Model):
    stakeholder = models.ForeignKey(User, related_name='tasks', blank=True, )
    project = models.ForeignKey(Project, related_name='project_tasks' )
    title = models.CharField(max_length=50, blank=True, null = True, )
    ...

class Scenario(models.Model):
    stakeholder = models.ForeignKey(User, related_name='scenarios', blank=True,)
    tasks = models.ManyToManyField(Task, blank=True)

Их сериалзеры:

class TaskSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField()
    class Meta:
        model = Task
        fields = '__all__'

class ScenarioSerializer(serializers.ModelSerializer):
    tasks = TaskSerializer(many=True, required=False)
    class Meta:
        model = Scenario
        fields = '__all__'

    def create(self, validated_data):
        tasks = validated_data.pop('tasks')
        instance = Scenario.objects.create(**validated_data)
        for task_data in tasks:
            task = Task.objects.get(pk=task_data.get('id'))
            instance.tasks.add(task)
        return instance

    def update(self, instance, validated_data):
        tasks = validated_data.pop('tasks', [])
        instance = super().update(instance, alidated_data)
        for task_data in tasks:
            task = Task.objects.get(pk=task_data.get('id'))
            instance.tasks.add(task)
        return instance

И представление для выполнения операций CRUD на обеих этих моделях:

@api_view(['GET', 'POST'])
def task_list(request):

    tasks = []
    """
    List all tasks, or create a new task.
    """
    if request.method == 'GET':
        #get all the tasks in  aspecific project
        if request.query_params.get('projectId'):
            # get a specific project 
            projectId = request.query_params.get('projectId')
            project = Project.objects.get(id=projectId)
            tasks = project.project_tasks.all()
            serializer = TaskSerializer(tasks, many=True)
            return Response(serializer.data)    
        else:
            tasks = Task.objects.filter(stakeholder=request.user)
            serializer = TaskSerializer(tasks, many=True)
            return Response(serializer.data)

    elif request.method == 'POST':
        serializer = TaskSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(stakeholder=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(
                serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET', 'PUT', 'DELETE'])
def task_detail(request, pk):
    """
    Get, udpate, or delete a specific task
    """
    try:
        task = Task.objects.get(pk=pk)
    except Task.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = TaskSerializer(task)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = TaskSerializer(task, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(
                serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        task.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

для сценария:

@api_view(['GET', 'POST'])
def scenarios_list(request):

    scenarios = []

    """
    List all scenarios, or create a new.
    """
    if request.method == 'GET':
        # get projects of a specific stakeholder
        if request.query_params.get('stakeholderId'):
            stakeholderId = request.query_params.get('stakeholderId')
            scenarios = Scenario.objects.filter(stakeholder=stakeholderId)
            serializer = ScenarioSerializer(scenarios, many=True)
            return Response(serializer.data)
        else:
            scenarios = Scenario.objects.all()
            serializer = ScenarioSerializer(scenarios, many=True)
            return Response(serializer.data)

    elif request.method == 'POST':
        serializer = ScenarioSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(stakeholder=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(
                serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET', 'PUT', 'DELETE'])
def scenario_detail(request, pk):
    """
    Get, udpate, or delete a specific scenarios
    """
    try:
        scenario = Scenario.objects.get(pk=pk)
    except Project.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = ScenarioSerializer(scenario)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = ScenarioSerializer(scenario, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(
                serilizer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        scenario.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Идея заключается в том, что сначала будут созданы задачи, а затем можно создать сценарий, добавив к нему несколько задач.

Создание сценария прошло успешно, но, поскольку я реализовал логику сценариев, создание и обновление задач указали на ошибку, вызвавшую ошибку Bad request.

запрос выглядит следующим образом:

{project: "6", title: "Fourteen", how_often: "", how_important_task: "", role: "", …} 

Нужно ли обновлять сериализатор задач? Что не так?

ОБНОВЛЕНИЕ: Если я прокомментирую id = serializers.IntegerField() в TaskSerializer Создание задачи выполнено успешно, но мне нужна эта строка, в противном случае создание сценария завершится неудачно.

1 Ответ

0 голосов
/ 29 апреля 2018

пожалуйста, удалите id из TaskSerializer и попробуйте:

class ScenarioSerializer(serializers.ModelSerializer):
    tasks = TaskSerializer(many=True, required=False)
    class Meta:
        model = Scenario
        fields = '__all__'

    def get_or_create_task(self, data):
        qs  = Task.objects.filter(pk=data.get('id'))
        if qs.exists():
            return qs.first()
        task = Task.objects.create(**data)
        return task

    def add_tasks(self, instance, tasks):
        for task_data in tasks:
            task = self.get_or_create_task(task_data)
            instance.tasks.add(task)

    def create(self, validated_data):
        tasks = validated_data.pop('tasks')
        instance = Scenario.objects.create(**validated_data)
        self.add_tasks(instance, tasks)
        return instance

    def update(self, instance, validated_data):
        tasks = validated_data.pop('tasks', [])
        instance = super().update(instance, alidated_data)
        self.add_tasks(instance, tasks)
        return instance

и почему вы не используете базовые представления классов для своего приложения?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...