Помогите расширить запрос в БД (Django)
Есть задача, включить в запрос все заказы которые ссылаются на имя товара, сделал запрос на получение коллекции имен товаров с аннотированными полями, но "прикрутить" туда выше упомянутое не выходит, подскажите плз куда копать!
вот модели:
class Order(models.Model):
number = models.IntegerField()
create_date = models.DateTimeField()
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
product_name = models.CharField(max_length=100)
product_price = models.DecimalField(max_digits=20, decimal_places=0, null=True, blank=True)
amount = models.IntegerField()
вот вьюха с запросом:
class ResultListView(ListView):
model = Order
success_url = reverse_lazy('top_results')
template_name = 'order/top_results.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
orders_set_sorted = OrderItem.objects.all() \
.annotate(name=Concat(Value('Товар - '), 'product_name', output_field=CharField())) \
.annotate(concat=Concat(Value('Заказ - '), 'order__number',
Value(', Цена - '), 'product_price',
Value(', Дата - '), 'order__create_date',
Value(';'), output_field=CharField()))\
.order_by('-product_name').distinct('product_name')
context['items'] = orders_set_sorted
return context
вот что выводит:
Товар-1; Заказ 1 - Цена 200 - Дата 01.01.2018 10:00;
вот то что я хочу получить:
Товар-1; Заказ 1 - Цена 200 - Дата 01.01.2018 10:00; Заказ N (который ссылается на Товар-1)- Цена 550 - Дата 10.01.2018 13:00; ...... + N заказов (которые ссылаются на Товар-1)
Ответы (2 шт):
Я бы на вашем месте не хранил данные о товаре в объекте позиции заказа. Это все таки разные вещи. Что вам нужно сделать (далее по тексту за точность кода не ручаюсь, так как на django давно ничего не писал; рассматривайте данный код как псевдо-код):
- Выделить отдельно класс товаров. Например как-то так:
class Product(models.Model):
caption = models.CharField(max_length=100)
price = models.DecimalField(max_digits=20, decimal_places=2, null=True, blank=True)
- В классе позиции заказа оставить только те значения, которые требуются для вычисления суммы, и ссылку на объект товара.
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='order_items')
value = models.IntegerField()
amount = models.DecimalField(max_digits=20, decimal_places=2, null=False, blank=False)
- Теперь вам не надо ничего придумывать для поиска всех заказов с конкретным товаром. Вы находите нужный товар, получаете все позиции заказов данного товара, а от них составляете список заказов.
def get_orders(product_caption):
product = Product.objects.get(caption = product_caption)
items = OrderItems.objects.filter(product = product)
orders = []
for it in items:
if not it.order in orders:
orders.append(it.order)
return orders
Для более глубоко понимания вопросов декомпозиции, советую почитать книг по философии ООП и основам реляционной теории.
Всетаки смог реализовать не создавая дополнительных таблиц и полей в базе :)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
orders_set_sorted = OrderItem.objects.all() \
.annotate(name=Concat(Value('Товар - '), 'product_name', output_field=CharField())) \
.annotate(concat=Concat(Value('Заказ - '), 'order__number',
Value(', Цена - '), 'product_price',
Value(', Дата - '), 'order__create_date',
output_field=CharField()))\
.order_by('-product_name')
queryset = orders_set_sorted.values('name').order_by('name')\
.annotate(
concat_=StringAgg('concat', delimiter='; '),
customer_name=F('name')
)
context['items'] = queryset
return context