问题 DRF 3 - 使用尽管表创建多对多更新/创建序列化程序


我正在尝试在DRF 3中创建一个参考应用程序来演示可以创建/更新模型的嵌套序列化程序。下面的示例代码在**之后使用“* create()参数进行炸弹,在尝试创建嵌套模型时必须是映射,而不是列表*”。我也不清楚我如何处理.update(),因为在某些情况下我只想建立其他关系(人)。

样本模型:

from django.db import models
class Person(models.Model):
    name = models.CharField(max_length=128)
class Group(models.Model):
    name = models.CharField(max_length=128)
    persons = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)

以及序列化器和视图集:

from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet
from app.models import Group, Person
class PersonSerializer(ModelSerializer):
    class Meta:
        model = Person
class GroupSerializer(ModelSerializer):
    persons = PersonSerializer(many=True)
    def create(self, validated_data):
        persons = validated_data.pop('persons')
        group = Group.objects.create(**validated_data)
        if persons: # Bombs without this check
            Person.objects.create(group=group, **persons)  # Errors here
        return group
    class Meta:
        model = Group

class PersonModelViewSet(ModelViewSet):
    serializer_class = PersonSerializer
    queryset = Person.objects.all()

class GroupModelViewSet(ModelViewSet):
    serializer_class = GroupSerializer
    queryset = Group.objects.all()

我试图POST一些JSON,插入一个具有两个(相关)人员的组:

{
   "persons": [
      { "name" : "name 1" },
      { "name" : "name 2" }
   ],
   "name": "group name 1"
}

8278
2018-02-24 20:56


起源



答案:


我不知道是否有更简单的方法,但我设法使其工作的唯一方法是在组序列化器中引用“通过”模型“成员资格”并为.create()和.update编写自定义代码( )。这似乎只是设置M2M FK的很多工作。如果有人知道更好的方式我会喜欢听到它。

class GroupMembershipSerializer(ModelSerializer):
    class Meta:
        model = Membership
        fields = ('person',)

class GroupCreateSerializer(ModelSerializer):
     memberships = GroupMembershipSerializer(many=True, required=False)

    def create(self, validated_data):
        person_data = validated_data.pop('memberships')
        group = Group.objects.create(**validated_data)
        for person in person_data:
            d=dict(person)
            Membership.objects.create(group=group, person=d['person'])
        return group

    def update(self, instance, validated_data):
        person_data = validated_data.pop('memberships')
        for item in validated_data:
            if Group._meta.get_field(item):
                setattr(instance, item, validated_data[item])
        Membership.objects.filter(group=instance).delete()
        for person in person_data:
            d=dict(person)
            Membership.objects.create(group=instance, person=d['person'])
        instance.save()
        return instance

    class Meta:
        model = Group

class GroupCreateModelViewSet(ModelViewSet):
    serializer_class = GroupCreateSerializer
    queryset = Group.objects.all()

因此,您可以使用以下方法创建一个包含相关人员的新组:

 { 
     "name" : "Group 1", 
     "memberships" : [ 
         { "person" : 1 },
         { "person" : 2 }
     ]
 }

9
2018-02-26 17:17



手指交叉,我可以得到这样的东西在类似的用例工作,将报告回来。 - seanmus


答案:


我不知道是否有更简单的方法,但我设法使其工作的唯一方法是在组序列化器中引用“通过”模型“成员资格”并为.create()和.update编写自定义代码( )。这似乎只是设置M2M FK的很多工作。如果有人知道更好的方式我会喜欢听到它。

class GroupMembershipSerializer(ModelSerializer):
    class Meta:
        model = Membership
        fields = ('person',)

class GroupCreateSerializer(ModelSerializer):
     memberships = GroupMembershipSerializer(many=True, required=False)

    def create(self, validated_data):
        person_data = validated_data.pop('memberships')
        group = Group.objects.create(**validated_data)
        for person in person_data:
            d=dict(person)
            Membership.objects.create(group=group, person=d['person'])
        return group

    def update(self, instance, validated_data):
        person_data = validated_data.pop('memberships')
        for item in validated_data:
            if Group._meta.get_field(item):
                setattr(instance, item, validated_data[item])
        Membership.objects.filter(group=instance).delete()
        for person in person_data:
            d=dict(person)
            Membership.objects.create(group=instance, person=d['person'])
        instance.save()
        return instance

    class Meta:
        model = Group

class GroupCreateModelViewSet(ModelViewSet):
    serializer_class = GroupCreateSerializer
    queryset = Group.objects.all()

因此,您可以使用以下方法创建一个包含相关人员的新组:

 { 
     "name" : "Group 1", 
     "memberships" : [ 
         { "person" : 1 },
         { "person" : 2 }
     ]
 }

9
2018-02-26 17:17



手指交叉,我可以得到这样的东西在类似的用例工作,将报告回来。 - seanmus


使用 PrimaryKeyRelatedField 如下所示:

http://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield

class GroupSerializer(serializers.ModelSerializer):
    persons = serializers.PrimaryKeyRelatedField(
        many=True, queryset=Person.objects.all())

    class Meta:
        model = Group
        fields = ('name', 'persons')

例如,首先创建每个人。 ID为1的人,姓名=“Bob”。 ID为2的人,姓名=“蒂姆”。然后使用他们将它们发布到REST端点 primary keys  所以:

# Group create() REST endpoint data to POST
{'name': 'my group', 'persons': [1, 2]}

现在,您之前创建的人员是该组的一部分。


7
2018-02-24 21:33



这是一个开始,但如何在一个POST中创建组和人员。看起来DRF 3处理嵌套更新,我只是不够明白这些例子。 - LiteWait
你的例子不适合我。它永远不会创建人员列表,它始终是空的。 - LiteWait
@LiteWait在这里,我的manytomany列表保持空白 - Programmingjoe
我的问题是我有read_only = True。我最终删除了它,然后需要一个查询集定义。 - Programmingjoe
@joe好的,我更新了我的答案删除 read_only=True 和 queryset。感谢您指出了这一点。 - Aaron Lelevier