Django - получить последний объект в каждом отношении - PullRequest
0 голосов
/ 01 октября 2018

Предположим, у меня есть модель 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)

, потому что это вернет всю статистику, которую я собрал за время.Как я могу ограничить запрос только самым последним для каждого продукта?

EDIT Я использую базу данных PostgreSQL.

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

У наборов запросов уже есть метод last() (и метод first() тоже FWIW).Единственный вопрос заключается в том, что вы хотите определить как «последний», так как это зависит от порядка набора запросов ... Но, предполагая, что вы хотите последний по дате создания (created поле), вы также можете использовать lastest()метод :

@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 заключается в использовании Manager (и, в конечном итоге, Queryset) для операций, работающих над всей таблицей поэтому вместо создания методов класса в вашей модели вы должны создать собственный менеджер:

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()
0 голосов
/ 01 октября 2018

Поместить метод в модель продукта и будет проще:

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] вернет только один объект моделиКласс.

например.

>>> 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'>
...