django rest m2m serializers throw Bad request error

时间:2018-04-28 12:14:16

标签: django django-rest-framework django-serializer

我有两个模型:任务和场景:

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)

for scenario:

@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)

我们的想法是首先创建任务,然后通过将一些任务附加到其中来创建一个场景。

场景创建是成功的,但是因为我实现了场景逻辑,任务创建和更新声明失败了我的错误请求错误。

请求如下所示:

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

我是否还需要更新任务序列化程序?出了什么问题?

更新:如果我在TaskSerializer中评论id = serializers.IntegerField()任务创建成功,但我需要该行,否则方案创建失败。

1 个答案:

答案 0 :(得分:1)

请从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

以及为什么不为您的应用使用类库视图?