简体   繁体   English

如何订购Django Rest Framework ManyToMany相关领域?

[英]How to order a Django Rest Framework ManyToMany related field?

I have a Django Rest Framework application with the following (simplified) models.py : 我有一个Django Rest Framework应用程序,其中包含以下(简化) models.py

class Photo(models.Model):
    ...

class Album(models.Model):
    ...
    photos = models.ManyToManyField(Photo, through='PhotoInAlbum', related_name='albums')

class PhotoInAlbum(models.Model):

    photo = models.ForeignKey(Photo)
    album = models.ForeignKey(Album)

    order = models.IntegerField()

    class Meta:
        ordering = ['album', 'order']

And in my serializers.py , I have the following: 在我的serializers.py ,我有以下内容:

class AlbumSerializer(serializers.ModelSerializer):

    ...
    photos = serializers.PrimaryKeyRelatedField('photos', many=True)

My question is, how can I have AlbumSerializer return the photos ordered by the field order ? 我的问题是,我如何让AlbumSerializer返回按字段order排序的照片?

The best solution to customise the queryset is using serializers.SerializerMethodField , but what shezi's reply is not exactly right. 自定义查询集的最佳解决方案是使用serializers.SerializerMethodField ,但shezi的回复并不完全正确。 You need to return serializer.data from SerializerMethodField . 您需要从SerializerMethodField返回serializer.data So the solution should be like this: 所以解决方案应该是这样的:

class PhotoInAlbumSerializer(serialisers.ModelSerializer):
    class Meta:
        model = PhotoInAlbum


class AlbumSerializer(serializers.ModelSerializer):
    # ...

    photos = serializers.SerializerMethodField('get_photos_list')

    def get_photos_list(self, instance):
        photos = PhotoInAlbum.objects\
            .filter(album_id=instance.id)\
            .order_by('order')\
            .values_list('photo_id', flat=True)

        return PhotoInAlbumSerializer(photos, many=True, context=self.context).data

It looks as if the RelatedManager that handles the relationship for ManyToManyFields does not respect ordering on the through model. 看起来处理ManyToManyFields关系的RelatedManager不遵循直通模型的排序。

Since you cannot easily add an ordering parameter to the serializer field, the easiest way to achieve ordering is by using a serializer method: 由于您无法轻松地将序列参数添加到序列化程序字段,因此实现排序的最简单方法是使用序列化程序方法:

class AlbumSerializer(serializers.modelSerializer):
    # ...

    photos = serializers.SerializerMethodField('get_photos_list')

    def get_photos_list(self, instance):
        return PhotoInAlbum.objects\
            .filter(album_id=instance.id)\
            .order_by('order')\
            .values_list('photo_id', flat=True)

Generally, the easiest way is to do this in your AlbumView or AlbumViewSet . 通常,最简单的方法是在AlbumViewAlbumViewSet执行此AlbumViewSet You can do this by filtering - in this case you should define a get_queryset method in your AlbumViewSet . 你可以做到这一点的过滤 -在这种情况下,你应该定义一个get_queryset在你的方法AlbumViewSet

Anyway, this is a good solution as long as you only GET the data. 无论如何,只要您只获取数据,这是一个很好的解决方案。 If you want to have POST and PUT methods working with ordering the photos, you can do it in two ways: 如果您希望POST和PUT方法与订购照片一起使用,您可以通过两种方式完成:

  • stay with ManyToMany relation - patch the create method in AlbumViewSet and __create_items and restore_object method in AlbumSerializer 留在ManyToMany的关系 -修补create的方法AlbumViewSet__create_itemsrestore_object的方法AlbumSerializer

or 要么

Note that the second solution does not mess with AlbumViewSet (and even AlbumSerializer !) - ordering logic stays in the relation field code. 请注意,第二个解决方案不会AlbumViewSet (甚至AlbumSerializer !) - 排序逻辑保留在关系字段代码中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM