Django Rest按id从多到多更新

2024-04-28 16:53:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我是python和django rest的新手。但我很困惑。在django rest框架中更新多对多关系的最佳方法是什么。 我读了文件 http://www.django-rest-framework.org/api-guide/relations/#manytomanyfields-with-a-through-model 默认情况下,针对指定了直通模型的ManyToManyField的关系字段设置为只读。

如果显式指定了一个关系字段,该字段指向带有直通模型的ManyToManyField,请确保将read_only设置为True。

如果我有密码

class Master(models.Model):
    # other fields  
    skills = models.ManyToManyField(Skill)

class MasterSerializer(serializers.ModelSerializer):
    skills = SkillSerializer(many=True, read_only=False)

这将返回作为对象列表的技能。我没有办法更新它们。据我所知,Django在M2M方面更喜欢使用objects和object id,如果我使用yii或rails,我将使用“through”模型。我想得到技能领域。我可以读和写。我可以做这个写操作

class MasterSerializer(serializers.ModelSerializer):
    skill_ids = serializers.ListField(write_only=True)

    def update(self, instance, validated_data):

    # ...
    validated_data['skill_ids'] = filter(None, validated_data['skill_ids'])
    for skill_id in validated_data['skill_ids']:
        skill = Skill.objects.get(pk=skill_id)
        instance.skills.add(skill)

    return instance

但我不能让它返回技能。为读写操作工作。


Tags: django模型resttrueidsonlydata关系
4条回答

tl;博士:

对于一个简单得多的线性解,对于M2M,我使用了如下形式的解:

serializer = ServiceSerializer(instance=inst, data={'name':'updated', 'countries': [1,3]}, partial=True)
if serializer.is_valid():
    serializer.save()

更完整的示例包括:

型号.py

from django.db import models

class Country(models.Model):
    name = models.CharField(max_length=50, null=False, blank=False)

class Service(models.Model):
    name = models.CharField(max_length=20, null=True)
    countries = models.ManyToManyField('Country')

序列化程序.py

from rest_framework import serializers
from .models import *

class CountrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Country
        fields = ('name',)

class ServiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Service
        fields = ('name', 'countries',)

确保为测试创建了一些虚拟服务和国家/地区实例。然后您可以更新函数中的实例,如下所示:

更新示例

# get an object instance by key:
inst = ServiceOffering.objects.get(pk=1)

# Pass the object instance to the serializer and a dictionary
# Stating the fields and values to update. The key here is
# Passing an instance object and the 'partial' argument:
serializer = ServiceSerializer(instance=inst, data={'name':'updated', 'countries': [1,3]}, partial=True)


# validate the serializer and save
if serializer.is_valid():
    serializer.save()   
    return 'Saved successfully!'
else:
    print("serializer not valid")
    print(serializer.errors)
    print(serializer.data)
    return "Save failed"

如果检查相关表,则会执行更新,包括M2M桥接表。

要扩展此示例,我们可以用非常类似的方式创建对象实例:

### Create a new instance example:
# get the potential drop down options:
countries = ['Germany', 'France']

# get the primary keys of the objects:
countries = list(Country.objects.filter(name__in=countries).values_list('pk', flat=True))

# put in to a dictionary and serialize:
data = {'countries': countries, 'name': 'hello-world'}
serializer = ServiceOfferingSerializer(data=data)

有几件事要注意。

首先,在您的示例中没有显式的直通表。所以你可以跳过那部分。

第二,您尝试使用的嵌套序列化程序比您要实现的要复杂得多。

您可以使用PrimaryKeyRelatedField简单地读/写相关id:

class MasterSerializer(serializers.ModelSerializer):
    skills_ids = serializers.PrimaryKeyRelatedField(many=True, read_only=False, queryset=Skill.objects.all(), source='skills')

应该能够读/写:

{id: 123, first_name: "John", "skill_ids": [1, 2, 3]}

注意,从JSON的“skill\u id”到模型的“skill s”的映射是通过使用可选的参数源完成的

我将尝试在设计方面带来一些启示:在Django中,如果为ManyToManyRelation指定模型,那么模型上的relation字段将变为只读。如果需要更改关联,可以直接在through模型上通过删除或注册新记录进行更改。

这意味着您可能需要为直通模型使用完全不同的序列化程序,或者编写自定义的更新/创建方法。

定制直通模型有一些缺陷,您确定您在ManyToManyFields的默认实现方面做得不够好吗?

有几件事要注意。

首先,在您的示例中没有显式的直通表。所以你可以跳过那部分。

第二,您尝试使用的嵌套序列化器远比您要实现的要复杂得多。

您可以使用PrimaryKeyRelatedField简单地读/写相关id:

class MasterSerializer(serializers.ModelSerializer):
    skills_ids = serializers.PrimaryKeyRelatedField(many=True, read_only=False, queryset=Skill.objects.all(), source='skills')

应该能够读/写:

{id: 123, first_name: "John", "skill_ids": [1, 2, 3]}

注意,从JSON的“skill\u id”到模型的“skill s”的映射是通过使用可选的参数源完成的

相关问题 更多 >