Как найти записи в базе данных, действительные с определенной даты
Требование
У меня есть проект, в котором я хочу хранить список цен для данного продукта, которые должны быть действительны после определенной даты. 'current_price' должна отображаться на странице администрирования списка продуктов (в зависимости от даты запроса)
Проблема
Моя текущая реализация приводит к чрезмерным запросам к базе данных
Пример
цены на продукцию с течением времени
| Product | valid from | Price |
|---|---|---|
| 1 | 2022-03-01 | 100 EUR |
| 1 | 2022-04-01 | 120 EUR |
| 1 | 2022-05-01 | 130 EUR |
| 2 | 2022-03-01 | 30 EUR |
| 2 | 2022-04-01 | 40 EUR |
| 2 | 2022-05-01 | 50 EUR |
ожидаемый результат
например, в 2022-03-15
| PRODUCT CODE | NAME | CURRENT PRICE |
|---|---|---|
| 2 | Second product | 30.00 |
| 1 | First Product | 100.00 |
например, на 2022-04-30
| PRODUCT CODE | NAME | CURRENT PRICE |
|---|---|---|
| 2 | Second product | 40.00 |
| 1 | First Product | 120.00 |
Код (рабочий)
Я получаю желаемые результаты при использовании следующего кода:
models.py
from django.db import models
class Product(models.Model):
product_code = models.PositiveIntegerField(primary_key=True)
name = models.CharField(max_length=100)
def __str__(self) -> str:
return self.name
class ProductPrice(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='prices')
valid_from = models.DateField()
price = models.DecimalField(max_digits=8, decimal_places=2)
class Meta:
get_latest_by = 'valid_from'
admin.py
from django.contrib import admin
from . import models
import datetime
@admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin):
list_display= ['product_code','name', 'current_price']
def current_price(self,product):
current_date = datetime.datetime.now()
return product.prices.filter(valid_from__lte=current_date).latest().price
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related('prices')
@admin.register(models.ProductPrice)
class ProductPriceAdmin(admin.ModelAdmin):
list_display=['product','valid_from', 'price']
Однако, это решение приводит к куче запросов к базе данных, так как фильтрация по valid_from__lte=current_date выполняется для каждого отдельного продукта:
1-й запрос
SELECT `playground_productprice`.`id`,
`playground_productprice`.`product_id`,
`playground_productprice`.`valid_from`,
`playground_productprice`.`price`
FROM `playground_productprice`
WHERE `playground_productprice`.`product_id` IN (2, 1)
следующие запросы
повторяется для каждого product_id
SELECT `playground_productprice`.`id`,
`playground_productprice`.`product_id`,
`playground_productprice`.`valid_from`,
`playground_productprice`.`price`
FROM `playground_productprice`
WHERE (`playground_productprice`.`product_id` = 2 AND `playground_productprice`.`valid_from` <= '2022-04-30')
ORDER BY `playground_productprice`.`valid_from` DESC
LIMIT 1
Есть ли лучший способ решить эту проблему?