Django-获取每个关系中的最新对象

时间:2018-10-01 08:03:45

标签: django postgresql django-orm

假设我的项目中有一个Product模型:

class Product(models.Model):
    price = models.IntegerField()

我想要一些统计信息(假设我想跟踪价格随时间的变化)

class ProductStatistics(models.Model):
    created = models.DateTimeField(auto_add_now=True)
    statistics_value = models.IntegerField()
    product = models.ForeignKey(Product)

    @classmethod
    def create_for_product(cls, product_ids):
        statistics = []
        products = Product.objects.filter(id__in=products_ids)
        for product in products:
            statistics.append(
                product=product
                statistics_value=product.price
            )
        cls.objects.bulk_create(statistics)

    @classmethod
    def get_latest_by_products_ids(cls, product_ids):
        return None

我在实现get_latest_by_products_ids方法时遇到问题。我只需要最新的统计信息,因此无法执行以下操作:

    @classmethod
    def get_latest_by_products_ids(cls, product_ids):
        return cls.objects.filter(product__id__in=product_ids)

因为这将返回我过去收集的所有统计信息。如何将查询限制为每个产品的最新查询?

编辑 我正在使用PostgreSQL数据库。

2 个答案:

答案 0 :(得分:2)

Querysets already have a last() method(以及first()方法也是FWIW)。唯一的问题是要定义为“最后一个”的内容,因为这取决于查询集的顺序...但是假设您要按创建日期最后一个(created字段),也可以use the lastest() method

@classmethod
def get_latest_by_products_ids(cls, product_ids):
    found = []
    for pid in products_ids:
        found.append(cls.objects.filter(product_id=pid).latest("created"))
    return found

请注意:Django's coding style is to use the Manager (and eventually the Queryset) for operations working on the whole table,因此应该在您的模型上创建自定义管理器,而不是在模型上创建类方法:

class productStatisticManager(models.Manager):

    def create_for_products(self, product_ids):
        statistics = []
        products = Product.objects.filter(id__in=products_ids)
        for product in products:
            statistics.append(
                product=product
                statistics_value=product.price
            )
        self.bulk_create(statistics)

    def get_latest_by_products_ids(cls, product_ids):
        found = []
        for pid in products_ids:
           last = self.objects.filter(product_id=pid).latest("created")         
           found.append(last)
        return found

class ProductStatistics(models.Model):
    created = models.DateTimeField(auto_add_now=True)
    statistics_value = models.IntegerField()
    product = models.ForeignKey(Product)

    objects = ProductStatisticManager()

答案 1 :(得分:0)

将方法放入产品模型中,将更加容易:

class Product(models.Model):
    price = models.IntegerField()

    def get_latest_stat(self):
        return self.productstatistics_set.all().order_by('-created')[0] # or [:1]

使用[:1]而不是[0]将返回单个元素的QuerySet,而[0]将仅返回模型类的一个Object。

例如

>>> type(cls.objects.filter(product__id__in=product_ids).order_by('-created')[:1])
<class 'django.db.models.query.QuerySet'>
>>> type(cls.objects.filter(product__id__in=product_ids).order_by('-created')[0])
<class 'myApp.models.MyModel'>