Django ORM , оптимизация запросов

Я создаю сайт электронной коммерции на Django и хотел оптимизировать свою базу данных, но столкнулся со следующей проблемой: У меня есть модель Order, которая имеет атрибуты свойств, такие как: overallamount и overallprice .Так что они делают много одинаковых запросов к базе данных, есть ли способ оптимизировать это .

models.py



class Product(models.Model):
    name = models.CharField(max_length=15)
    price = models.IntegerField()
    digital = models.BooleanField(default=False)
    image = models.ImageField(upload_to='store/', null=True, blank=True)

    def __str__(self):
        return self.name


class Order(models.Model):
    customer = models.ForeignKey(Customer, default=None, null=True, on_delete=models.SET_NULL)
    completed = models.BooleanField(default=False)
    date_ordered = models.DateField(auto_now=True)

    @property
    def overallprice(self):
        return sum([item.totalprice for item in self.orderitem_set.all()])

    @property
    def overallamount(self):
        return sum([item.quantity for item in self.orderitem_set.all()])

    def __str__(self):
        return str(self.customer)


class OrderItem(models.Model):
    order = models.ForeignKey(Order, null=True, on_delete=models.SET_NULL)
    date_ordered = models.DateField(auto_now=True)
    product = models.ForeignKey(Product, default=None, null=True, on_delete=models.SET_NULL)
    quantity = models.IntegerField(default=0)

views.py



@login_required(login_url='login')
def cart(request):
    order, created = Order.objects.get_or_create(customer=request.user.id)
    orderitem = OrderItem.objects.filter(order=order).select_related('product')

    return render(request, 'cart.html', {'orderitem': orderitem, 'order': order})

и шаблон/cart.html

{%extends 'layout.html'%}
{% load static %}

{%block content%}

<div class="box-element">
    <a  class="btn btn-outline-dark" href="{% url 'menu' %}">&#x2190; Continue Shopping</a>
    <br>
    <br>
    <table class="table">
        <tr>

            <th><h5>Items:<strong>{{order.overallamount}}</strong></h5></th>
            <th><h5>Total:<strong>${{order.overallprice}}</strong></h5></th>

            <th>
                <a  style="float:right; margin:5px;" class="btn btn-success" href="{% url 'checkout' %}">Checkout</a>
            </th>
        </tr>
    </table>
</div>


<div class="box-element">
    <div class="cart-row">
        <div style="flex:2"></div>
        <div style="flex:2"><strong>Item</strong></div>
        <div style="flex:1"><strong>Price</strong></div>
        <div style="flex:1"><strong>Quantity</strong></div>
        <div style="flex:1"><strong>Total</strong></div>
    </div>
{%for item in orderitem%}
    <div class="cart-row">
        {%if item.product.image%}
        <div style="flex:2"><img class="row-image" src="{{item.product.image.url}}"></div>
        {%else%}
            <div style="flex:2"><img class="row-image" src="{% static 'images/placeholder.png' %}"></div>
        {%endif%}


        <div style="flex:2"><p>{{item.product}}</p></div>
        <div style="flex:1"><p>${{item.product.price}}</p></div>
        <div style="flex:1">
            <p class="quantity">{{item.quantity}}</p>
            <div class="quantity">
                <img class="chg-quantity update-cart"    data-action="add" data-product='{{item.product.id}}' src="{% static  'images/arrow-up.png' %}">

                <img class="chg-quantity update-cart" data-action="remove" data-product='{{item.product.id}}' src="{% static  'images/arrow-down.png' %}">
            </div>
        </div>
        <div style="flex:1"><p>${{item.totalprice}}</p></div>
    </div>
{%endfor%}
{%endblock%}

если я не использую order.overallamount и order.overallprice, количество запросов равно 5, но когда я их использую, то 13. Я пробовал следующее:


@login_required(login_url='login')
def cart(request):
    order, created = Order.objects.get_or_create(customer=request.user.id)[0].prefetch_related('overallprice','overallamount')

    orderitem = OrderItem.objects.filter(order=order).select_related('product')

    return render(request, 'cart.html', {'orderitem': orderitem, 'order': order}) 

выдает ошибку типа: 'Order' object has no attribute 'select_related'

Вот мой Django-Tool-Bar:

SELECT --- FROM "menu_orderitem" WHERE "menu_orderitem". "order_id" = '1' 3 похожих запроса. Дублируется 3 раза. SELECT --- FROM "menu_product" WHERE "menu_product". "id" = '2' LIMIT 21 6 похожих запросов.

Ваши методы overallprice и overallamount всегда будут делать запрос.

Если производительность является вашей главной заботой, я бы рекомендовал преобразовать эти два метода в поля вашей модели и обновлять их каждый раз, когда меняется цена или, например, обновляется ордер. Вы также можете написать пользовательскую миграцию для автоматического заполнения этих новых полей с помощью вашей текущей реализации методов.

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

Если вы просто хотите преодолеть эту ошибку, пожалуйста, опубликуйте трассировку стека. Подсказкой может быть то, что после использования prefetch_related вам больше не нужно запрашивать OrderItems, вы должны быть в состоянии получить порядок элементов по: order.order_items где order_items если вы связали имя. Дополнительная информация о related_name.

Вернуться на верх