【问题标题】:How to create custom output JSON from two serializers如何从两个序列化程序创建自定义输出 JSON
【发布时间】:2019-05-17 16:48:24
【问题描述】:

我是 Django 中 Rest Framework 的新手,我有一个练习。我想从两个 Django 模型创建自定义 JSON 输出。我已经创建了两个序列化视图。输出 JSON 应该是:

{

    "movie_id": 2,

    "total_comments": 4,

    "rank": 1

},

{

    "movie_id": 3,

    "total_comments": 2,

    "rank": 2

},

{

    "movie_id": 4,

    "total_comments": 2,

    "rank": 2

}

GET /top url 应该:

  • ​应根据在指定日期范围内添加到电影(如示例中)的 cmets 数量返回数据库中已存在的热门电影排名。响应应包括电影 ID、排名位置和 cmets 总数(在指定日期范围内)。

  • cmet 数量相同的电影在排名中的位置应该相同。

  • 应要求指定生成统计信息的日期范围。

我有两个序列化器:

class CommentSerializer(serializers.ModelSerializer):
   class Meta:
      model= Comment
      fields=('movie','user','timestamp','content','approved')
class MovieSerializer(DynamicFieldsModelSerializer,serializers.HyperlinkedModelSerializer):
     comments=CommentSerializer(many=True)
     comments=None

    class Meta:
        model = Movie

        fields = ('id','name','description','year','released','comments','rating')

这是评论模型:

class Comment(models.Model):
     movie = models.ForeignKey(Movie, on_delete=models.DO_NOTHING,related_name='comments',blank=True,null=True)
    content = models.TextField()
    timestamp = models.DateTimeField(default=timezone.now)
    user=models.CharField(max_length=250)

我试图通过这个技巧自己做到这一点:

class MovieViewSet(viewsets.ModelViewSet):

      queryset = Movie.objects.all()
      serializer_class = MovieSerializer

class CommentViewSet(viewsets.ModelViewSet):
      queryset = Comment.objects.all()
      serializer_class = CommentSerializer
class TopViewSet(viewsets.ModelViewSet):
      serializer_class = MovieSerializer
      #queryset = Movie.objects.annotate(comment_count=(Count('comments'))).order_by("-comment_count","-rating")
       queryset = Movie.objects.all().annotate(comment_count=(Count('comments'))).order_by("-comment_count")

但我不知道如何创建自定义 JSON 输出

如果有人能在最后一点(即日期)也帮助我,我将不胜感激。

【问题讨论】:

    标签: python django serialization django-rest-framework


    【解决方案1】:

    我认为你可以这样做:

    # serializer
    class MovieSerializer(HyperlinkedModelSerializer):
         comments = CommentSerializer(many=True)
         comments_count = serializer.IntegerField()
         rank = serializer.IntegerField()
    
        class Meta:
            model = Movie
            fields = ('id','name','description','year','released','comments','rating', 'comments_count', 'rank')
    
    # Viewset
    
    from django.db.models import Sum, F
    from django.db.models.expressions import Window
    from django.db.models.functions import Rank
    
    
    class TopViewSet(viewsets.ModelViewSet):
          serializer_class = MovieSerializer
          queryset = Movie.objects.all()
    
           def get_queryset(self, *args, **kwargs):
              from_date = self.request.query_params.get('from_date')
              to_date = self.request.query_params.get('to_date')
              movies = super(ToViewSet, self).get_queryset()
              if from_date and to_date:
                   movies = movies.filter(release__range=[from_date, to_date])
              return movies.annotate(comment_count=Count('comments'), rank=Window(expression=Rank(), order_by=F('comments').desc()),)
    

    说明:

    get_queryset() 方法中,我使用了self.request.query_params.get(...)。这用于获取URL Querystring。因此,当您调用/your_url/?from_date=2018-01-01&to_date=2019-01-31 时,它将过滤给定日期范围之间的查询集。

    另外,我使用了 Django 模型的Window Function 来标注对象的等级。

    最后,在序列化程序中,我在Serializer 中添加了两个额外的字段。它将从查询集中捕获带注释的值并显示为输出。

    【讨论】:

    • 你是我的救星,但我有最后一个小问题。我试图实现你的代码,我认为在这行代码中有语法错误:return movies.annotate(comment_count=Count('cmets'),rank=Window(expression=Rank(), order_by=F('cmets) ').asc()), ) 语法接近 "(" RawErrorCode: dpaste.com/2KC41XG
    • 嗯,我在本地机器上运行了我的代码,但没有遇到任何问题。您能否检查一下它的制表符/空格转换问题,或者您是否遗漏了任何括号:)?
    • 你能只给我views.py文件吗?请
    • 没关系,这是 sqlite 3 数据库的问题。非常感谢,你是最棒的。
    • 不客气。顺便说一句,您可以标记this answer as accepted,这可能会对其他人有所帮助。
    【解决方案2】:

    我认为你应该在你的视图中重写 get 方法:

    from rest_framework.response import Response
    from rest_framework import status
    
    
    
    
    
    class MovieViewSet(viewsets.ModelViewSet):
    
        queryset = Movie.objects.all()
        serializer_class = MovieSerializer
        def get(self):
            """ do some thing"""
            output = {{    
                        "movie_id": 2,
                        "total_comments": 4,
                        "rank": 1
                       },
                       {
                        "movie_id": 3,
                        "total_comments": 2,
                        "rank": 2
                       },
                       {
                        "movie_id": 4,
                        "total_comments": 2,
                        "rank": 2
                        }
                       }
            return Response(output, status=status.HTTP_200_OK)
    

    更多详情请阅读 DRF 文档: https://www.django-rest-framework.org/api-guide/generic-views/#generic-views

    【讨论】:

    • 我不知道我们是否相互理解,但问题是我不知道如何结合这两个模型来创建自定义 JSON 输出。 REST API 应该创建一个排行榜,我认为计算 cmets,并根据 cmets 的数量和指定的日期范围显示排名。
    • @KrzysiekPerkowski 你的模型中有这种关系吗?
    • 是的,评论模型中的外键
    • 我的关系有问题吗?你可以解释吗?非常感谢您的帮助
    • 你能上传你的结果吗?
    猜你喜欢
    • 2015-01-06
    • 2013-08-03
    • 2017-03-02
    • 2019-05-07
    • 2016-11-21
    • 2012-12-27
    • 2019-11-27
    • 2016-11-28
    • 1970-01-01
    相关资源
    最近更新 更多