【问题标题】:Django: Trying to get last field's value from another table (FK) and add to my modelDjango:试图从另一个表(FK)中获取最后一个字段的值并添加到我的模型中
【发布时间】:2014-07-15 09:15:30
【问题描述】:

我有 2 个表,关系是一对多的,“Book”(id,name,author)->“BookStatus”(id,status,date)。我想在查询集中获取所有书籍的最后状态(根据字段“日期”)。我怎样才能做到这一点?

在那之后,我如何通过我的模型“Book”显示该字段(状态),例如 Book.last_status。

提前致谢

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    不幸的是,通过 ORM 实现这一点并不容易。原因是为此所需的 SQL 异常复杂。首先您需要获取最新状态日期,然后加入与该状态匹配的状态。

    如果您只需要访问 Python 端的最新状态,那么您可以使用 book.statuses.latest()(为每个模型生成一个查询),或者可能是模型上的一个属性:

    @property
    def latest_status(self):
        latest_status = None
        for status in self.statuses.all():
            if latest_status is None or latest_status.date < status.date:
                latest_status = status
        return latest_Status
    

    现在您可以在 Python 端使用 latest_status 来获取图书的最新状态。如果在取书的时候加上prefetch_related,访问latest_status不会产生查询。

    如果您在查询时需要访问最新状态,事情变得更加复杂。我经常使用一种解决方案,我在数据库中创建最新项目的视图,然后通过 ORM 使用这些视图。所以,在数据库中是这样的:

    CREATE VIEW latest_book_status_view AS (
        SELECT null AS id,
               book_status.book_id,
               book_status.id AS status_id
          FROM book_status
         WHERE book_status.date = (SELECT max(inner_status.date)
                                     FROM book_status inner_status
                                    WHERE inner_status.book_id = book_status.book_id)
    );
    

    在models.py中:

    class LatestBookStatus(models.Model):
        # Note the null id column above. It will be used as fake primary key
        # for this model.
        book = models.OneToOneField(Book, null=True, on_delete=models.DO_NOTHING, related_name='latest_status')
        status = models.OneToOneField(BookStatus, null=True, on_delete=models.DO_NOTHING)
    
        class Meta:
            db_table = "latest_book_status_view"
            managed = False
    

    现在您应该能够在过滤状态时发出查询:

    Book.objects.filter(latest_status__status__date__gte=today())...
    

    您可以通过以下方式获取最新状态:

    qs = Book.objects.select_related('latest_status__status')
    # access it
    qs[0].latest_status.status.date
    

    不幸的是,这种设置很复杂,并且存在一些问题。例如,在测试时,您将需要某种方式来生成测试数据库中的视图。 Django 1.7 迁移和 RunSQL 操作是执行此操作的一种方法。

    简而言之:如果您需要访问 Python 端的最新状态,请使用属性方法。如果您需要访问 SQL 端的最新状态,请为更复杂的解决方案做好准备。上面给出了一种可能的解决方案。

    【讨论】:

      【解决方案2】:

      请务必设置好related_name 并为BookStatus 设置正确的get_latest_by

      books = Book.objects.prefetch_related('statuses')
      books[0].statuses.latest()
      

      【讨论】:

      • 这不是正确的方法,books[0].statuses.latest() 会生成另一个查询,而不是使用预取的值。
      • @akaariai 那你会怎么做呢?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-08
      • 1970-01-01
      相关资源
      最近更新 更多