Django - 以一对多关系选择嵌套集合平均值与分组

Posted

技术标签:

【中文标题】Django - 以一对多关系选择嵌套集合平均值与分组【英文标题】:Django - Select nested collection Avg with group by in one to many relationship 【发布时间】:2018-09-10 06:13:40 【问题描述】:

我有以下模型,我想要选择一个业务集合,每个业务都有一个基于 group by review_question_id 的 AVG(rate) 集合。

以下是必要的模型:

class ReviewQuestion(models.Model):
    """Represents a question to be given in a business type
    """
    business_type = models.ForeignKey(BusinessType, on_delete=models.CASCADE)
    question_text = models.CharField(max_length=100)


class Business(models.Model):
    """Values for a specific business, based on a type
    will inherit questions and reviews
    """
    business_type = models.ForeignKey(BusinessType, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)


class CustomerReview(models.Model):
    """Rate value by customers on a specific quesiton
    for a specific business
    """
    business = models.ForeignKey(Business, on_delete=models.CASCADE)
    review_question = models.ForeignKey(
        ReviewQuestion, on_delete=models.CASCADE)
    review_value = models.PositiveSmallIntegerField()

我试图接近的最近的查询:

items = Business.objects.filter(business_type_id=type_id).values(
        'id', 'name', 'business_type_id', 'address', 'customerreview__review_question_id').annotate(rate=Avg('customerreview__review_value'))

它的问题是重复。它复制了整个列表,结果是扁平的,就像你用扁平 tsql 编写它时得到的一样。

理想的结果应该是这样的:

[
    
        "business_id": 1,
        "business_name": "something",
        "rating":[
            
                "Question_1":
                    "title":"ReviewQuestion__question_text",
                    "Avg":5.0
                ,
                "Question_2":
                    "title":"ReviewQuestion__question_text",
                    "Avg":5.0
                ,
                    ...
                
            
        ]
    
]

如果我是 python/django 的新手,我将不胜感激。

【问题讨论】:

【参考方案1】:

如果你使用 django-rest-framework 会很容易。 您应该使用两个序列化程序。

from rest_framework import serializers

class BussnessSerializer(serializers.ModelSerializer):
     rating = QuestionWithRatingSerializer(
                  source='reviewquestion_set', 
                  many=True
     )
     business_id = serializers.IntegerField(source='id')
     business_name = serizlizers.CharField(source='name')


     class Meta:
           model = Business
           fields = ('rating', 'business_id', 'business_name')


class QuestionWithRatingSerializer(serializers.ModelSerializer):
      title = serializers.CharField(source='question_text')
      avg = serizlizers.SerializerMethodField()

      def get_avg(self, obj):

          return obj.customerreview_set.aggregave(
                     avg=Avg('review_value')['avg'])

      class Meta:
           model = ReviewQuestion
           fields = ('title', 'avg')

【讨论】:

您好,感谢您的回复,因为我说我是新来的。这应该是某种 ViewModel(例如 c# linq viewModels)还是我应该更改我的模型以匹配它? 啊,不。我关注的是来自 docs.djangoproject.com 的文档,而不是来自 rest-framework 的文档.. 如果你愿意,你可以在你的 django 项目中使用 django-rest-framework(django-rest-framework.org)

以上是关于Django - 以一对多关系选择嵌套集合平均值与分组的主要内容,如果未能解决你的问题,请参考以下文章

Django模型加入一对多关系以在模板中显示

具有三层深度嵌套模型的查询集过滤器(多个一对多关系)

如何以 django 形式过滤多对多字段

Django 表关系的创建

Django Postgres ArrayField 与一对多关系

RestKit嵌套的一对多关系映射很慢