【问题标题】:Save a many-to-many model in Django/REST?在 Django/REST 中保存多对多模型?
【发布时间】:2014-08-27 05:56:42
【问题描述】:

我正在为我的 Django 应用程序编写 REST API,但无法让 POST 请求在一个模型上工作。 这是有问题的模型:

class ProjectNode(models.Model):
    name = models.CharField(max_length=60)
    place = models.CharField(max_length=150)
    time_spent = models.BigIntegerField()
    parent_project = models.ForeignKey(Project, related_name='tasks')
    workers = models.ManyToManyField(User, related_name='tasks_can_do')

    def __str__(self):
        return self.name

User 模型目前只包含一个 name 字段。 这是我的ProjectNode 序列化程序:

class ProjectNodeSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProjectNode
        fields = ('id', 'name', 'place', 'time_spent', 'workers',)

这是 API 视图(来自views.py):

class WebProjectNodeListView(generics.ListCreateAPIView):
    queryset = ProjectNode.objects.all()
    serializer_class = ProjectNodeSerializer

    def pre_save(self, obj):
        obj.parent_project = Project.objects.get(pk=self.request.DATA['parent_project'])
        for worker_pk in self.request.DATA['workers']:
            obj.workers.add(User.objects.get(pk=worker_pk))
        obj.final_worker = User.objects.get(pk=self.request.DATA['final_workers'])

我昨天尝试了一个更简单的版本,它只有Project ForeignKey关系,它似乎可以工作,所以我认为使用add也可以,但是我在测试API时出错使用httpie(我已经添加了一些用户和项目,并且确信我得到了他们的正确ID)。 这是请求:

http POST :8000/api/tasks/ name="newtask" place="home" time_spent:=50 parent_project:=1 workers:=[1]

我得到这个错误:

"<ProjectNode: newtask>" needs to have a value for field "projectnode" before this many-to-many relationship can be used.

而且traceback也指向这行代码:

obj.workers.add(User.objects.get(id=worker_pk))

现在,我感觉这是因为我试图在数据库中创建 ProjectNode 对象之前更新 User 对象上的关系,但我不确定如何解决这个问题?

【问题讨论】:

  • 看来你的预感是正确的。要么覆盖 post 并以正确的顺序完成所有拯救自己的工作,或者通过覆盖 post_save 来拯救你的员工关系
  • 覆盖post_save 也不起作用。
  • 你有没有深究过这个?
  • @Pureferret 不,我最终为具有 ManyToMany 字段的模型上的 POST 请求编写了自己的处理程序。
  • 你能不能比回答一下?

标签: python django rest many-to-many django-rest-framework


【解决方案1】:

DRF 不能创建嵌套序列化程序对象或多对多字段的模型。 因此有必要在创建 ProjectNode 之前覆盖 Serializer 创建方法并创建/获取 M2M 模型。 尝试在您的序列化程序中覆盖 create(self, validated_data) 并在此方法中处理您的数据..

例子:

我的模型项目与 ProjectImages 具有 M2M 关系。在 ProjectSerializer 中,我重写了这样的创建方法。

 def create(self, validated_data):
        try:
            # Remove nested and M2m relationships from validated_data
            images = validated_data.pop('projectimage_set') if 'projectimage_set' in validated_data else []

            # Create project model
            instance = Project(**validated_data)
            if status:
                instance.set_status(status)

            project = instance.save()

            # Create relations
            for image in images:
                ProjectImage.objects.create(project=project, **image)

        except exceptions.ValidationError as e:
            errors_messages = e.error_dict if hasattr(e, 'error_dict') else e.error_list
            raise serializers.ValidationError(errors_messages)

        return project

希望对您有所帮助!

【讨论】:

    猜你喜欢
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    相关资源
    最近更新 更多