代码之家  ›  专栏  ›  技术社区  ›  akaphenom

修改Django Rest Framework中序列化程序的输出

  •  4
  • akaphenom  · 技术社区  · 12 年前

    我正在使用django-rest框架来输出一篇文章的内容。它运行得很好,只是现在我想修改行为,不返回完整的“内容”,而是一个预告片(比如内容的前200个字符,但理想情况下我希望能够添加任何逻辑,比如200个字符后的第一句话的结尾):

    class ArticleSerializer(serializers.HyperlinkedModelSerializer):
        user = UserSerializer(many=False, read_only=True)
    
        class Meta:
            model = models.Article
            fields = (
                'id'
                ,'title'
                , 'date_added'
                , 'content'
                , 'user'
            )
    

    我查看了GenericAPIView,在那里我认为可能有一些东西需要覆盖——但没有什么看起来很明显——有人能提供一些见解吗?提前谢谢

    2 回复  |  直到 12 年前
        1
  •  5
  •   mariodev    12 年前

    我很确定这正是你所需要的:

    http://django-rest-framework.org/api-guide/fields.html#serializermethodfield

    class ArticleSerializer(serializers.HyperlinkedModelSerializer):
        user = UserSerializer(many=False, read_only=True)
        teaser = serializers.SerializerMethodField('get_teaser')
    
        class Meta:
            model = models.Article
            fields = (
                'id'
                ,'title'
                , 'date_added'
                , 'user'
                , 'teaser'
            )
    
        def get_teaser(self, obj):
            return force_text(obj.content[:20])
    
        2
  •  2
  •   akaphenom    12 年前

    我接受mariodev的解决方案——因为它确实有效,而且是我最初的想法。我确实扩展了我的需求,并希望将预告片功能应用到其他领域,因此我最终得到了:

    from django import forms
    from rest_framework.compat import force_text
    from rest_framework import serializers, fields
    
    class TeaserField(fields.Field):
    
        def __init__(self, teaser_length=None, original_field=None):
            self.teaser_length = teaser_length
            self.original_field = original_field
            super(fields.Field, self).__init__()
    
        def field_to_native(self, obj, field_name):
            if(self.original_field != None):
                field_name = self.original_field
    
            value = getattr(obj, field_name)
            return self.to_native(value)
    
        def to_native(self, value):
            def joinEm(chunk):
                teaser = ''
                i=0
                while len(teaser) < self.teaser_length:
                    teaser += chunk[i] + '.'
                    i += 1
    
                return teaser
    
            chunk = value.split('.')
            teaser = joinEm(chunk)
    
            strongOpenTag = '<strong>'
            strongOpen = teaser.find(strongOpenTag)
            strongClose = teaser.find('</strong>')
    
            if(strongOpen > 0 and strongClose < 0):
                teaser  = teaser.replace(strongOpenTag,'')
    
            return force_text(teaser)
    

    以前的解决方案

    这是我目前的工作解决方案,很想知道对此的意见。

    from django import forms
    from rest_framework.compat import force_text
    
    class TeaserField(fields.CharField):
        def __init__(self, teaser_length=None, *args, **kwargs):
            self.teaser_length = teaser_length
            super(TeaserField, self).__init__(*args, **kwargs)
    
        def to_native(self, value):
            return force_text(value[:self.teaser_length])
    
    
    class ArticleSerializer(serializers.HyperlinkedModelSerializer):
        user = UserSerializer(many=False, read_only=True)
        content = TeaserField(teaser_length=20)
        class Meta:
            model = models.Article
            fields = (
                'id'
                ,'title'
                , 'date_added'
                , 'content'
                , 'user'
            )
    
    
    class IdeaSerializer(serializers.HyperlinkedModelSerializer):
        user = UserSerializer(many=False, read_only=True)
        teaser = myFields.TeaserField(teaser_length=200, original_field='content')
    
        class Meta:
            model = myModels.Idea
            fields = (
                'id'
                ,'title'
                , 'date_added'
                , 'user'
                , 'content'
                , 'teaser'
            )