如何在django-rest中使用M2M关系

Dra*_*ter 5 django-rest-framework

让我们从django文档中使用的关于M2M关系的模型开始,该模型使用through参数指向将充当中介的模型.

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, 
                                     through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()

    class Meta:
        ordering = ['date_joined']
Run Code Online (Sandbox Code Playgroud)

现在假设我想为Group模型提供一个休息读写视图,该视图还包含每个组内的所有Person,按date_joined字段排序.我想获得的json序列化如下(成员只用他们的id描述):

{
    "id": 1, 
    "name": "U2", 
    "members": [
       20, 
       269, 
       134, 
       12,
    ]
}
Run Code Online (Sandbox Code Playgroud)

我写了一个序列化器:

class GroupSerializer(serializers.ModelSerializer):
    members = serializers.SlugRelatedField(source='membership_set', 
                                           many=True, 
                                           read_only=False,
                                           slug_field='person_id', 
                                           required=True)

    class Meta:
        model = Group
        fields = ('id', 'name', 'members')
Run Code Online (Sandbox Code Playgroud)

虽然对于读取操作它运行良好,但它不适用于写入.我应该如何定义序列化程序,以便在给定上面定义的序列化的情况下,它将继续:

  1. 创建组对象
  2. 将每个成员添加到组(通过创建Membership对象)

Ade*_*laN 2

这里您可以看到您尝试执行的操作仅适用于读取操作。正如其创建者 Tom Christie 在此评论中所述,这是 DRF 的一个常见问题。

此外,对于您想要的 JSON 序列化,建议使用 PK 相关字段,如此处所示尽管这对创建 Group 对象和添加成员没有帮助。您必须自己编写该代码。

希望这可以帮助。

编辑

通过创建成员资格将每个人添加到组中的代码片段:

def post_save(self, obj, created=False):
    # obj represents the Group object
    if created:
        # Test to see if the Group was successfully created
        members = self.request.DATA.get('members', None)
        if members not None:
            for id in members:
                person = Person.objects.get(id=id)
                membership, m_created = Membership.objects.get_or_create(person=person, group=obj)
                # Here you can use m_created to see if the membership already existed and to do whatever else you need.
Run Code Online (Sandbox Code Playgroud)

此实现假设您已使用auto_now声明了 date_joined 。如果没有,您也应该将其作为参数传递。