Json 如何使用django rest框架修改多对多集合

Json 如何使用django rest框架修改多对多集合,json,django,django-rest-framework,many-to-many,Json,Django,Django Rest Framework,Many To Many,我正在尝试创建一个端点,在该端点中,拥有用户实体,我可以将现有的组实体添加/删除到用户.组多对多字段。但当我尝试这样做时,django rest框架尝试创建新的组对象,而不是查找现有的组对象 我定义了两个序列化程序,其中UserSerializer具有嵌套的GroupSerializer: class GroupSerializer(serializers.ModelSerializer): class Meta: model = Group fields

我正在尝试创建一个端点,在该端点中,拥有
用户
实体,我可以将现有的
实体添加/删除到
用户.组
多对多字段。但当我尝试这样做时,django rest框架尝试创建新的组对象,而不是查找现有的组对象

我定义了两个序列化程序,其中
UserSerializer
具有嵌套的
GroupSerializer

class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = Group
        fields = ['id', 'name']


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'groups']

    groups = GroupSerializer(many=True)

    def update(self, instance, validated_data):
        data = validated_data.copy()
        groups = data.pop('groups', [])
        for key, val in data.items():
            setattr(instance, key, val)
        instance.groups.clear()
        for group in groups:
            instance.groups.add(group)
        return instance

    def create(self, validated_data):
        data = validated_data.copy()
        groups = data.pop('groups', [])
        instance = self.Meta.model.objects.create(**data)
        for group in groups:
            instance.groups.add(group)
        return instance
当我通过PUT REST调用(从django REST框架web界面)发送JSON时:

我希望序列化程序找到具有给定id的组并将其添加到用户。但是,它尝试创建一个新的用户组,但失败,出现重复密钥错误:

{
    "groups": [
        {
            "name": [
                "group with this name already exists."
            ]
        }
    ]
}
我在互联网上搜索并调试了自己,但没有找到这个用例的解决方案

UserSerializer
类中的
create
update
方法永远不会到达

编辑:按要求,以下是我的视图和URL:

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer


class GroupViewSet(viewsets.ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
网址:


这似乎是由于包含唯一约束的嵌套序列化程序模型导致的验证错误,请参见此。根据文章,DRF没有处理这种情况,因为很难知道序列化程序是否是另一个序列化程序中的嵌套序列化程序。这就是为什么
create()
update()
从未到达,因为验证是在调用它们之前完成的

解决此问题的方法是在
GroupSerializer
中手动删除唯一性验证器,如下所示:

class GroupSerializer(serializers.ModelSerializer):
类元:
模型=组
字段=['id','name']
额外费用={
'name':{'validators':[]},
}
顺便说一句,在您的
update()
create()
代码中有一些地方可以改进或应该纠正。首先,您没有执行
instance.save()
,因此在整个过程完成后不会更新实例。其次,
只是一个字典列表,您不应该以这种方式添加对象。以下是根据您的OP代码进行的修改:

def更新(自身、实例、已验证的_数据):
数据=已验证的数据。复制()
groups=data.pop('groups',[])
对于键,data.items()中的val:
setattr(实例、键、值)
instance.save()#这确实会更新数据库值
组id=[g['id']表示组中的g]
instance.groups.clear()
instance.groups.add(*group_id)#一次添加所有组。也可以将这两行替换为
#instance.groups.set(组ID)
返回实例

请提供已调试的视图和URL,并发现问题不在于视图/URL。
serializer.save()
方法是引发异常的地方。更具体地说,
serializer.is\u valid()
。我不想用不必要的信息把问题弄得杂乱无章(可读性会降低)。初始化序列化程序对象的方式将导致执行
serializer.save()
的不同流程。这就是为什么我建议您提供查看功能,因为初始化可以在查看功能中完成。谢谢,我不知道!我编辑了问题并添加了视图和URL。您是如何发送请求的?由于您使用的是
ModelViewSet
,并且没有覆盖其中的任何方法,只使用默认路由器,因此触发序列化程序的方式将取决于您使用的HTTP方法。在本例中,您希望执行
update()
,这意味着您应该在此处使用
PUT
方法。如果您使用
POST
,则将调用
create()
。感谢您提供答案、代码改进提示以及相关帖子的链接!我发现行
组id=[g['id']代表组中的g]
-基本上,
验证的组数据有
组:[OrderedDict([('name','AAA')])]
所以我现在必须使用
名称
而不是
id
(直到我找到一种方法让
id
不丢失)。有趣的是,
id
request.data
中,但在序列化程序的
validated\u data
中不存在。你是对的。那是我的错。我忘记了
id
不会出现在
validated\u data
中,因为它默认设置为
read\u only=True
(如果您没有指定额外的配置)。因此,您确实应该在这里使用
name
,而不是
id
我尝试了
id=serializers.IntegerField(read\u only=False)
,但
id
仍然不存在于
验证的\u数据中。我发现它工作的唯一方法是使用:
serializers.ModelField(model\u field=Group()。\u meta.get\u field('id'))
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer


class GroupViewSet(viewsets.ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)


urlpatterns = [
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]