【发布时间】:2021-09-12 23:54:40
【问题描述】:
我有菜肴(食谱)、其中的配料、配料价格、上菜日期、该日期这道菜的订单(全、双、半)。 所以我需要结合格式的成分购物清单: 土豆 5个 柠檬3个
表格:
class IngredientType(models.Model):
name = models.CharField(max_length=100, verbose_name="Тип ингредиента")
picture = models.ImageField(verbose_name="Изображение типа ингредиента")
def __str__(self):
return f"Тип ингредиента: {self.name}"
class Supplier(models.Model):
name = models.CharField(max_length=100, verbose_name="Имя поставщика")
picture = models.ImageField(verbose_name="Изображение поставщика")
description = models.TextField(verbose_name="Описание поставщика")
phone = models.CharField(max_length=100, verbose_name="Телефон поставщика")
site = models.CharField(max_length=100, verbose_name="Сайт поставщика")
address = models.CharField(max_length=200, verbose_name="Адрес поставщика")
def __str__(self):
return f"Поставщик {self.name}"
class Ingredient(models.Model):
"""Ingredient model"""
name = models.CharField(max_length=255, verbose_name="Имя ингредиента", unique=True)
measure = models.CharField(max_length=30, verbose_name="Размерность")
price = models.DecimalField(
decimal_places=2,
verbose_name="Цена ингредиента",
max_digits=10,
default=0,
)
type = models.ForeignKey(
IngredientType,
on_delete=models.SET_DEFAULT,
default=None,
verbose_name="Тип ингредиента",
related_name="ingredients",
)
supplier = models.ForeignKey(
Supplier,
on_delete=models.SET_DEFAULT,
default=None,
verbose_name="Поставщик",
related_name="ingredients",
)
def __str__(self):
return f"Ингредиент: {self.name} ({self.measure})"
class DishType(models.Model):
name = models.CharField(max_length=100, verbose_name="Тип блюда")
picture = models.ImageField(verbose_name="Изображение типа блюда")
def __str__(self):
return f"Тип блюда {self.name}"
class Dish(models.Model):
name = models.CharField(
default="New Dish", verbose_name="Имя блюда", max_length=100
)
picture = models.ImageField(verbose_name="Изображение блюда")
description = models.TextField(verbose_name="Описание блюда")
price = models.DecimalField(
decimal_places=2, verbose_name="Цена блюда", max_digits=10
)
date_created = models.DateTimeField(auto_now_add=True)
type = models.ForeignKey(
DishType,
on_delete=models.SET_DEFAULT,
default=None,
verbose_name="Тип блюда",
related_name="dishes",
)
ingredients = models.ManyToManyField(
Ingredient, related_name="dishes", through="IngredientAmount"
)
def __str__(self):
return f"{self.name} по цене {self.price}"
class IngredientAmount(models.Model):
"""Support model for Ingredient&Recipe ManyToMany relation"""
dish = models.ForeignKey(
Dish, on_delete=models.CASCADE, related_name="amounts", verbose_name="Dish"
)
ingredient = models.ForeignKey(
Ingredient,
on_delete=models.CASCADE,
related_name="amounts",
verbose_name="Ingredient",
)
amount = models.DecimalField(
max_digits=5, decimal_places=1, verbose_name="Сколько штук"
)
def __str__(self):
return f"Количество: {self.ingredient.name} by {self.amount}"
class DishDateLink(models.Model):
dish = models.ForeignKey(
Dish, on_delete=models.SET_DEFAULT, default=None, related_name="dish_date_links"
)
date = models.DateField(verbose_name="Дата планируемой подачи блюда")
is_ready = models.BooleanField(default=False)
def __str__(self):
return f"{self.dish.name} запланировано на {self.date}. Готовность: {self.is_ready}"
class Transaction(models.Model):
dish_date_link = models.ForeignKey(
DishDateLink,
on_delete=models.SET_DEFAULT,
default=None,
verbose_name="Дата и блюдо",
related_name="transactions",
)
amount = models.DecimalField(
default=0, decimal_places=2, verbose_name="Сумма транзакции", max_digits=19
)
serving = models.DecimalField(
default=1,
decimal_places=2,
verbose_name="Размер порции (0.5, 1, 2)",
max_digits=19,
)
user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="transactions"
)
date_created = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
self.user.cash -= self.amount
self.user.save()
super(Transaction, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
self.user.cash += self.amount
self.user.save()
super(Transaction, self).delete(*args, **kwargs)
def __str__(self):
return f"{self.user.get_full_name()} заказал {self.dish_date_link.dish.name} на {self.amount}"
我做了这个查询:
queryset = Ingredient.objects.values("name").annotate(
sum=F("amounts__amount") * Sum("dishes__dish_date_links__transactions__serving") * F("price")
).filter(sum__gt=0).order_by('-sum')
计算正确,但它不会对成分本身进行分组,它们是重复的。 请帮我把它们结合起来。 现在输出:
GET /api/v1/ingredient-sums/
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"name": "Potato",
"sum": "600.00"
},
{
"name": "Potato",
"sum": "500.00"
},
{
"name": "Rice",
"sum": "90.00"
}
]
【问题讨论】:
-
我想你一定已经尝试过
.distinct,但它会引发错误。我记得在一个项目中遇到了同样的问题,所以我所做的就是将distinct('id')放入查询中,然后稍后使用普通 python 对结果进行排序。 -
我试过
queryset = Ingredient.objects.values("name").annotate( sum=Sum("amounts__amount", distinct=True) * Sum("dishes__dish_date_links__transactions__serving") * F("price") ).filter(sum__gt=0).order_by('-sum'),但输出总和不正确[ { "name": "Potato", "sum": "2800.00" }, { "name": "Rice", "sum": "90.00" } ] -
你能不能试着把 distinct('id') 放在这里而不是 order_by。但它只有在你不使用 SQLite 时才有效
-
annotate() + distinct(fields) 没有实现。
标签: python django postgresql orm