使用Django ORM查询一个Model,其中两个FK通过第三个Model上的unique_together约束相关

disbfnqx  于 11个月前  发布在  Go
关注(0)|答案(2)|浏览(91)

我目前正面临着一个挑战,那就是创建一个QuerySet来准确地表示我的Django模型中的关系。我有一个模型配备了两个外键,FK 1和FK 2。当这两个外键组合在一起时,会创建一个表示分类的元组(FK 1,FK 2-> CLS.pk)。这个关系是通过另一个模型来管理和表示的,其中存储了与这些外键对应的记录以及生成的分类(FK 1,FK 2,CLS.pk)。
定义我的问题本身就是一个挑战,所以我试图简化关系,以说明我在这里试图实现的核心思想。

class Event(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=11, default=0.0)
    event_date = models.DateField()
    local = models.ForeignKey(Local, on_delete=models.CASCADE, related_name='event_set')
    origin = models.ForeignKey(Origin, on_delete=models.CASCADE, related_name='event_set')

    class Meta:
        db_table = 'db_event'
        
class Local(models.Model):
    name = models.CharField(max_length=100, unique=True)

    class Meta:
        db_table = 'db_local'
        
class Origin(models.Model):
    name = models.CharField(max_length=100, unique=True)

    class Meta:
        db_table = 'db_origin'
        
class Classification(models.Model):
    name = models.CharField(max_length=100, unique=True)

    class Meta:
        db_table = 'db_classification'
        
class ClassificationPerOriginAndLocal(models.Model):
    local = models.ForeignKey(Local, on_delete=models.CASCADE, related_name='classification_related_set')
    origin = models.ForeignKey(Origin, on_delete=models.CASCADE, related_name='classification_related_set')
    classification = models.ForeignKey(Classification, on_delete=models.CASCADE, related_name='classification_related_set')
    
    class Meta:
        db_table = 'db_classification_per_origin_and_local'
        unique_together = ('local', 'origin',)

字符串
考虑一个“事件”模型,用于存储发生在特定起源和特定本地的事件的记录。稍后,我需要对每个事件进行分类,这种分类是通过元组“起源”和“本地”实现的。
这个分类系统是通过第三个名为“ClassificationPerOriginAndLocal”的模型来管理的,在这个模型中,我指定哪个“Classification”对象对应于给定的“origin”和“local”对象。
在一个SQL原始查询中,我会用这样的公式来获得“Classification.pk”:

SELECT
        ev.*,
        clsf.classification_id
    FROM db_event as ev 
    INNER JOIN db_classification_per_origin_and_local as clsf
     ON clsf.local_id = ev.local_id
      AND clsf.origin_id = ev.origin_id


如何使用Django ORM创建这个查询?

qhhrdooz

qhhrdooz1#

from django.db.models import F

events_with_classification = Event.objects.annotate(
    classification_id=F('local__classification_related_set__classification_id')
)

# Now, you can access the classification_id field for each Event object
for event in events_with_classification:
    classification_id = event.classification_id

字符串
您应该能够访问查询集中每个“Event”的“classification_id”字段,并且它将包含“ClassificationPerOriginAndLocal”模型中指定的“Classification.pk”。

jslywgbw

jslywgbw2#

在深入研究了其他Stack Overflow线程和Django文档很长时间之后,我设法通过使用Subquery and OuterRef解决了这个问题:

from django.db.models import OuterRef, Subquery

# Creating the subquery
subquery = (
    ClassificationPerOriginAndLocal
    .objects
    .filter(local=OuterRef('local'), origin=OuterRef('origin'))
)

# Constructing the final query with annotation
final_query = (
    Event
    .objects
    .annotate(classification=Subquery(subquery.values('classification')))
)

字符串
对于上下文,我发现的解决方案确保子查询只返回每个关系的奇异值(local + origin -> classification)。这是通过利用local + origin的唯一约束(使用unique_together设置)来强制执行的。
此外,如果你需要访问分类对象中的特定字段,你可以使用Django的'__'查找来实现:

final_query = (
    Event
    .objects
    .annotate(
        classification=Subquery(subquery.values('classification')),
        classification__name=Subquery(subquery.values('classification__name')
    )
)

相关问题