简体   繁体   English

Django Rest PUT请求序列化程序无法使用外键更新模型

[英]Django rest PUT request serializer fails to update model with foreign key

I have two models like following: 我有以下两种模型:

class Task(models.Model):
    user = models.ForeignKey(User, blank=True)
    what_task = models.CharField(max_length=100, )

    #This helps to print in admin interface
    def __str__(self):
        return u"%s" % (self.what_task)


class Step(models.Model):
    task = models.ForeignKey(Task, related_name='steps', on_delete=models.CASCADE, )
    what_step = models.CharField(max_length=50, blank=True, )

    #This helps to print in admin interface
    def __str__(self):
        return u"%s" % (self.what_step)

And I have written serializers: 我写了序列化器:

class StepSerializer(serializers.ModelSerializer):
    class Meta:
        model = Step
        exclude = ('task',)

class TaskSerializer(serializers.ModelSerializer):
    steps = StepSerializer(many=True)
    class Meta:
        model = Task
        fields = '__all__'


    def create(self, validated_data):
        steps_data = validated_data.pop('steps')
        task = Task.objects.create(**validated_data)
        for step_data in steps_data:
            Step.objects.create(task=task, **step_data)
        return task 

    def update(self, instance, validated_data):
        steps_data = validated_data.pop('steps')

        instance.what_task = validated_data.get('what_task', instance.what_task)
        instance.how_often = validated_data.get('how_often', instance.how_often)
        instance.how_important = validated_data.get('how_important', instance.how_important)
        instance.why_perform = validated_data.get('why_perform', instance.why_perform)
        instance.why_important = validated_data.get('why_important', instance.why_important)
        instance.possible_improvement = validated_data.get('possible_improvement', instance.possible_improvement)
        instance.existing_solutions = validated_data.get('existing_solutions', instance.existing_solutions)
        instance.how_important_improvement = validated_data.get('how_important_improvement', instance.how_important_improvement)
        instance.advantages_of_improvement = validated_data.get('advantages_of_improvement', instance.advantages_of_improvement)

        instance.save()
        for step_data in steps_data:
            Step.objects.update(task=task, **step_data)
        return instance 

My view: 我的观点:

@api_view(['GET', 'POST'])
def task_list(request):
    """
    List all tasks, or create a new task.
    """
    if request.method == 'GET':
        print(request.user)
        tasks = Task.objects.filter(user=request.user.id)
        serializer = TaskSerializer(tasks, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = TaskSerializer(data=request.data)
        print(request.data)
        if serializer.is_valid():
            serializer.save(user=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, id):
    """
    Get, udpate, or delete a specific task
    """
    try:
        task = Task.objects.get(id=id)
    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(user=request.user)
            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)

My GET and POST requests works correct (first function in views), my tasks and associated steps are created in a single request however PUT request is wrong, I am not sure if I am updating the steps correctly; 我的GETPOST请求工作正常(视图中的第一个功能),我的任务和相关步骤在单个请求中创建,但是PUT请求错误,我不确定我是否正确更新了这些步骤; if I comment out from serializer the for loop, task is updated successfully. 如果我从serializer的for循环中注释掉,任务将成功更新。

What and how should I modify so that I can update a specific task with associated steps? 我应该修改什么以及如何修改,以便可以通过相关步骤更新特定任务?

In your for loop, you update every existing task (inside update , you set the new values): 在for循环中,您更新每个现有任务(在update ,设置新值):

Step.objects.update(task=task, **step_data)

Instead, before the loop, you should delete all steps for that task and create the new steps: 相反,在循环之前,您应该删除该任务的所有步骤并创建新步骤:

...
    Step.objects.filter(task=instance).delete()
    for step_data in steps_data:
        Step.objects.create(task=instance, **step_data)
...

A more efficient approach would be to find all steps that do not exists (based on id) in validated_data and delete them, update the steps with an id, an create those without ids. 一种更有效的方法是在validated_data找到所有不存在的步骤(基于id)并将其删除,使用id更新这些步骤,然后创建一个没有id的步骤。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM