Django模型设计模式 - 获得最年轻的相关对象

发布于 2025-02-07 05:59:34 字数 868 浏览 1 评论 0 原文

django让您关注关系 link link ,但是,没有一种过滤方法可让您获得最小的/最古老的方法,或者最大/分钟,Afaik。

laravel具有“ 拥有许多”之一> ,我希望django在不需要窗口函数的情况下,有自己的局限性。

尽管有希望,但注释也是一个死胡同。

因此,我想知道以下情况的最佳设计是什么:

我有“模型A”,其实例将在其生命周期(创建”,“处理”,“完整”)期间通过多个状态。我想知道A当前具有的模型实例的状态,但也有记录每个状态何时有效。我不想解析日志。

我认为一种很好的方法是创建一个状态模型(B),其外键是模型是一个实例。何时开始和停止每个状态时,很容易看出。

但是,如果我想在所有模型A实例中获取当前状态(一个模型B的实例),则需要进行N+1个数据库查询。这似乎是最佳的。

有什么选择?

Django lets you follow relations link, but none of the filter methods let you get youngest/oldest, or max/min, afaik.

Laravel has "has one of many", and I wish that Django had something similar without requiring window functions, that have their own limitations.

Annotations despite being promising, are also a dead end.

Therefore I wonder what the best design is for the following situation:

I have "model A", whose instances will pass through several statuses during their lifecycle ("created", "processing", "complete"). I want to know what status an instance of model A currently has, but also have a record of when each status was in effect. I don't want to parse logs.

I thought a good approach was to create a status model (model B) whose foreign key is a model A instance. it becomes easy to see when each status was started and stopped.

However if I want to get the current status (an instance of model B) for all my model A instances, I need to do n+1 database queries. This seems sub-optimal.

What are some alternatives?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

愚人国度 2025-02-14 05:59:34

但是,如果我想为所有模型A实例获得当前状态(模型B的实例),我需要进行n+1个数据库查询。这似乎是最佳的。

no ,您可以使用 subquery 表达式  [django-doc] 。实际上,如果您有两个模型:

class Item(models.Model):
    name = models.CharField(max_length=128)


class ItemStatus(models.Model):
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    status = models.CharField(max_length=128)
    started = models.DateTimeField(auto_now_add=True)

您可以用以下状态注释每个 item

from django.db.models import OuterRef, Subquery

Item.objects.annotate(
    last_status=Subquery(
        ItemStatus.objects.filter(
            item_id=OuterRef('pk')
        ).order_by('-started').values('status')[:1]
    )
)

对于每个 item ,将有一个额外的属性命名 .last_status < /code>将包含 .status 的相关 itemstatus 。如果没有这样的 statusitem ,<代码> last_status 将为 none null )。

这将由数据库端的 subqueries 确定,因此在您检索 item s的相同查询中完成。不遭受 n+1问题

However if I want to get the current status (an instance of model B) for all my model A instances, I need to do n+1 database queries. This seems sub-optimal.

No, you can make use of Subquery expressions [Django-doc]. Indeed, if you have two models:

class Item(models.Model):
    name = models.CharField(max_length=128)


class ItemStatus(models.Model):
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    status = models.CharField(max_length=128)
    started = models.DateTimeField(auto_now_add=True)

You can annotate each Item with the last status with:

from django.db.models import OuterRef, Subquery

Item.objects.annotate(
    last_status=Subquery(
        ItemStatus.objects.filter(
            item_id=OuterRef('pk')
        ).order_by('-started').values('status')[:1]
    )
)

For each Item, there will be an extra attribute named .last_status that will contain the .status of the related ItemStatus that started last. If there is no such StatusItem, last_status will be None (NULL).

This will be determined by subqueries at the database side, hence it is done in the same query where you retrieve the Items, and thus does not suffer from the N+1 problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文