如何在Django模型中拥有一个字典字段,并在字典键之间使用聚合(最小/最大)来利用该字段

2024-04-27 22:16:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在django1.9中构建一个模型,该模型具有一个键、值对(dictionary)字段,该字段还允许查询集聚合(min、mix等)。 我尝试过使用JSONField:

#models.py
from django.contrib.postgres import fields as pgfields
class Entry(models.Model):
    pass

class Scorer(models.Model):
    name = models.CharField(max_length=100)

class EntryScoreSet(models.Model):
    scorer = models.ForeignKey(Scorer)
    entry = models.ForeignKey(Entry, related_name="scorecard")
    scores = pgfields.JSONField(default={})
....
# shell test
import random
entry = Entry()
scorer,_ = Scorer.objects.get_or_create(name="scorer1")
entry.save()
for i in range(0,10):
    scores = dict(scoreA=random.random(),
                  scoreB=random.random(),
                  scoreC=random.random(),
                  )
    entry_score_set=EntryScoreSet(scores=scores, entry=entry, scorer=scorer)
    entry_score_set.save()

entry.scorecard.filter(scorer="scorer1").aggregate(Max("scores__scoreA"))

但是我遇到了来自this ticket的错误(基本上,不支持聚合)。在

第二种选择是使用键、值对模型(类似于this answer):

^{pr2}$

但我不知道如何在查询集中为特定的键值获取聚合。在

我该如何在Django中实现一个键、值对字段,该字段允许对特定键的值的查询集进行聚合?在

编辑:

下面是一个片段,它演示了我想使用pandas和第二个选项(key,pair model)执行的操作:

import django_pandas.io as djpdio
scds=Scorecard.objects.filter(
        entry__in=Entry.objects.order_by('?')[:10],
        scorer__name="scorer1")
scorecard_base=djpdio.read_frame(scds,fieldnames=["id","entry__id","scorer__name","scores__id"])
scores=djpdio.read_frame(Score.objects.filter(scorecard__in=scds),fieldnames=["id","key","value"])
scorecard_=(scorecard_base
        .merge(scores,left_on="scores__id",right_on="id")        
        .pivot_table(index="entry__id",columns="key",values="value").reset_index())
scorecard=scorecard_base.merge(scorecard_,on="entry__id")
scorecard["scoreA"].max()

使用django的ORM是否可以实现这种情况?与使用pandas pivot函数相比,效率如何?在


Tags: djangonameimportidmodelobjectsmodelsrandom
1条回答
网友
1楼 · 发布于 2024-04-27 22:16:05

您可以使用conditional expressions,使用您提出的第二个模型结构(Score和一个{}的外键)。在

from django.db.models import Case, When, Max, FloatField

entry.scorecard.all().annotate(
    max_score_key1=Max(
        Case(
            When(scores__key='key1', then='scores__value'),
            default=0,
            output_field=FloatField()
        )
    ),
    max_score_key2=Max(
        Case(
            When(scores__key='key2', then='scores__value'),
            default=0,
            output_field=FloatField()
        )
    )
)

这将向结果的max_score_key1对象添加一个max_score_key1属性,这为所有Scoreskey的{}提供最大值。类似地,max_score_key2用于Scores,与{}等


编辑:根据注释中的对话,您似乎希望在整个查询集中获得Score中每个键的最大值。你可以这样做:

^{pr2}$

这将为您提供如下输出:

[
    {'scores__key': 'key1', 'scores__value__max': 16.0}, 
    {'scores__key': 'key2', 'scores__value__max': 15.0},
    ....
]

相关问题 更多 >