且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

DRF 3 - 通过表创建多对多更新/创建序列化程序

更新时间:2022-10-15 12:24:49

我没有线索,如果有一个更简单的方法,但我设法使这个工作的唯一方法是引用通过模型成员资格在组序列化程序中并编写.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')
对于validated_data中的项目:
如果Group._meta.get_field(item):
setattr(instance,item,validated_data [item])
Membership.objects.filter(group = instance).delete()
person_data中的person:
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:组1,
会员资格:[
{person:1},
{person:2}
]
}


I am trying to create a reference app in DRF 3 to demonstrate a nested serializer that can create/update models. The sample code below bombs with "*create() argument after ** must be a mapping, not list*" when trying to create the nested models. It is also no clear to me how I'd handle the .update() as in some cases I just want to be establish additional relationships (Persons).

The sample models:

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)

And the serializers and viewsets:

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()

I am trying to POST some JSON that inserts a Group with two (related) Persons:

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

I have no clue if there is an easier way, but the only way I managed to get this to work is to reference the 'through' model "memberships" in the Group serializer and write custom code for .create() and .update(). This seems like a lot of work to just set M2M FK's. If someone knows a better way I'd love to hear it.

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()

So you can create a new Group with related Person(s) using:

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