【问题标题】:DRF 3 - Creating Many-to-Many update/create serializer with though tableDRF 3 - 使用虽然表创建多对多更新/创建序列化程序
【发布时间】:2015-04-26 16:22:55
【问题描述】:

我正在尝试在 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()

我正在尝试发布一些 JSON 来插入一个包含两个(相关)人员的组:

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

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    我不知道是否有更简单的方法,但我设法让它工作的唯一方法是在 Group 序列化程序中引用“通过”模型“成员资格”并为 .create() 编写自定义代码和。更新()。设置 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 }
         ]
     }
    

    【讨论】:

    • 手指交叉,我可以让这样的东西在类似的用例中工作,将报告。
    • 改用批量创建。
    【解决方案2】:

    使用此处显示的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 的人,姓名 = “Tim”。然后使用他们的primary keys 将它们发布到 REST 端点所以:

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

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

    【讨论】:

    • 这是一个开始,但是如何在单个 POST 中创建组和人员。似乎 DRF 3 处理嵌套更新,我只是不够聪明,无法理解这些示例。
    • 你的例子对我不起作用。它从不创建人员列表,它始终为空。
    • @joe DRF 不支持嵌套创建。如果数据库中已经存在person 记录,并且您正在尝试创建一个新的group 并拥有与之相关的person 记录,那么上面的有效负载:{'name': 'my group', 'persons': [1, 2]} 将创建一个新的group 和将现有的person 记录与它关联为manytomany。希望有帮助
    • 我的问题是我的 read_only=True。我最终删除了它,然后需要一个查询集定义。
    • @joe 好的,我更新了我的答案以删除 read_only=Truequeryset。感谢您指出这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-25
    相关资源
    最近更新 更多