How to work with M2M relationship in django-rest

2019-05-01 15:57发布

问题:

Let's start from the models used in the django docs about the M2M relationship that uses the through argument to point to the model that will act as an intermediary.

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']

Assume now I want to have a rest read-write view for the Group model which contains also all the Person inside each group, ordered by date_joined field. The json serialization I would like to obtain is the following (the members are described only with their id):

{
    "id": 1, 
    "name": "U2", 
    "members": [
       20, 
       269, 
       134, 
       12,
    ]
}

I wrote a serializer:

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

While for read operations it works well, it doesn't for writing. How should I define the serializer so that, given the above defined serialization, it will proceed by:

  1. Create the Group object
  2. Add each members to the Group (by creating a Membership object)

回答1:

From here you can see that what you are trying to do works only for read operations. This is a common problem for DRF, as stated by its creator, Tom Christie, in this comment.

Also, for the JSON serialization that you want, it is recommended to use a PK related field, as shown here, though that won't help with creation of the Group object and adding of members. You will have to write that code yourself.

Hope this helps.

Edit

Code snippet for adding each person to the Group by creating Memberships:

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.

This implementation assumes that you have declared your date_joined with auto_now. If not, you should also pass it in as a parameter.