【问题标题】:Django RestFramework group byDjango Rest 框架组
【发布时间】:2015-09-13 07:41:28
【问题描述】:

我的问题与 Django RestFramework 有关,是关于如何对元素进行分组。

这是我的 serializers.py

from collaborativeAPP.models import *
from rest_framework import serializers

class VocabSerializer(serializers.ModelSerializer):
    term_word = serializers.CharField(source='term.word',read_only=True)
    kwdGroup = serializers.StringRelatedField()
    class Meta:
        model = Vocab
        fields = ('id','term_word', 'meaning','kwdGroup')

class TermSerializer(serializers.ModelSerializer):
    word = serializers.CharField(read_only=True)
    class Meta:
        model = Term
        fields = ('url', 'word')

下面的json是实际结果:

{"results":[
            {
                "id": 5,
                "term_word": "word1",
                "meaning": "Text1"
                "kwdGroup": "A"
            },
            {
                "id": 6,
                "term_word": "word2",
                "meaning": "Text2"
                "kwdGroup": "A"
            },
            {
                "id": 7,
                "term_word": "word3",
                "meaning": "Text3"
                "kwdGroup": "A"
            }
        ]}

你可以注意到“kwdGroup”是一个重复的元素,我要分组。

我想按 kwdGroup 分组

{"A":[
       {
        "id": 5,
        "term_word": "word1",
        "meaning": "Text1"
        },
        {
        "id": 6,
        "term_word": "word2",
        "meaning": "Text2"
        },
        {
        "id": 7,
        "term_word": "word3",
        "meaning": "Text3"
        }
    ]
}

我正在寻找关于 api 指南的 http://www.django-rest-framework.org/ 的答案,但我很难找到一种方法来引导它。 你有同样的问题吗?你有什么建议我该怎么做?您有任何使用 Django RestFramework 处理元素分组的示例吗?

提前致谢。

【问题讨论】:

  • 如何获得“实际”结果?请添加视图的代码,或用于获取数据的查询
  • Sylvain,对于我的问题,您不需要评估代码。如果您知道 django RestFramework,您只需要知道 DjangoRestFrameWork 是否提供此功能。有几个脚本有助于构建这个 json(serializer.py、models.py、views.py、urls.py),显示所有这些是没有意义的。我可以证明可以帮助的是现在更新的序列化程序。
  • 我最近遇到了同样的问题。我只是避免使用序列化程序,并覆盖视图的 get 方法以直接生成 JSON 输出。我想知道是否有办法用序列化器巧妙地做到这一点。我实际上有 2 个级别的分组要做。

标签: json xml django django-rest-framework


【解决方案1】:

假设kwdGroup 字段是与名为KeyWordGroup 的模型的关系字段。

默认ListSerializer 使用to_representation 方法来呈现序列化对象列表rest_framework

class ListSerializer(BaseSerializer):
     ...

    def to_representation(self, data):
        """
          List of object instances -> List of dicts of primitive datatypes.
        """
        # Dealing with nested relationships, data can be a Manager,
        # so, first get a queryset from the Manager if needed
        iterable = data.all() if isinstance(data, models.Manager) else data

        return [
            self.child.to_representation(item) for item in iterable
        ]

我们可以修改ListSerializer对结果进行分组,例如:

class VocabListSerializer(serializers.ListSerializer):

    def to_representation(self, data):
        iterable = data.all() if isinstance(data, models.Manager) else data
        return {
            kwdGroup: super().to_representation(Vocab.objects.filter(kwdGroup=kwdGroup))
            for kwdGroup in KeyWordGroup.objects.all()
        }

然后我们可以将修改后的VocabListSerializerVocabSerializer 一起使用。

class VocabSerializer(serializers.Serializer):
...
    class Meta:
        list_serializer_class = VocabListSerializer

【讨论】:

    【解决方案2】:

    实现此目的的一种方法是使用SerializerMethodField。以下可能与您的用例略有不同,但您可以相应地采用。还有其他方法可以实现这一点,包括覆盖 to_representation 方法,但它们依赖于弄乱 DRF 的内部工作,而不是此处相关。

    models.py

    class Dictionary(Model):
        id = PrimaryKey
    
    
    class Word(Model):
        dictionary = ForeignKey(Dictionary, related_name='words')
        word = Charfield()
        group = Charfield()
    

    serializers.py

    class WordSerializer(serializers.ModelSerializer):
        word = serializers.CharField(read_only=True)
    
        class Meta:
                model = Word
                fields = ('word',)
    
    
    class DictionarySerializer(serializers.ModelSerializer):
        group_a = serializers.SerializerMethodField()
        group_b = serializers.SerializerMethodField()
    
        def get_group_a(self, instance):
            return WordSerializer(instance.words.filter(group='a'), many=True).data
    
        def get_group_b(self, instance):
            return WordSerializer(instance.words.filter(group='b'), many=True).data
    
        class Meta:
            model = Dictionary
            fields = ('group_a', 'group_b')
    

    一个例子

    >>> my_dictionary = Dictionary.objects.create()
    >>> Word.objects.bulk_create(
            Word(word='arrow', group='a' dictionary=my_dictionary),
            Word(word='apple', group='a' dictionary=my_dictionary),
            Word(word='baby', group='b' dictionary=my_dictionary),
            Word(word='banana', group='b' dictionary=my_dictionary)
    )
    >>> serializer = DictionarySerializer(my_dictionary)
    >>> print serializer.data
    {
        'group_a': {
            'word': 'arrow',
            'word': 'apple'
        },
        'group_b': {
            'word': 'baby',
            'word': 'banana'
        },
    }
    

    【讨论】:

    • 你能用动态数量的不同组进行这项工作吗?
    • 它可以工作,但是如果您以这种方式使用嵌套序列化程序,它将大大增加响应时间。
    【解决方案3】:

    您可能会使用“序列化关系”,尤其是“嵌套关系”。见文档here

    【讨论】:

    • 这并没有回答与根据组类型对父元素中的元素进行分组相关的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    • 2016-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 2017-11-09
    相关资源
    最近更新 更多