Как можно удалить объект, если другой объект является emty?

Итак, я начинающий кодер, разрабатывающий проект электронной коммерции на Django. Мне удалось добавить функцию "delete item" для удаления товаров из корзины. Однако, когда товар удаляется, заказ не удаляется. OrderItem и Order - это две отдельные модели, я бы хотел, чтобы когда OrderItem полностью удален и корзина пуста, сам заказ тоже удалялся. Я прикреплю код моделей и функций.

Модель заказа:

class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)

def __str__(self):
    return str(self.id)
    
@property
def get_cart_total(self):
    orderitems = self.orderitem_set.all()
    total = sum([item.get_total for item in orderitems])
    return total 

@property
def get_cart_items(self):
    orderitems = self.orderitem_set.all()
    total = sum([item.quantity for item in orderitems])
    return total 

МодельOrderItem:

class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)

@property
def get_total(self):
    total = self.product.price * self.quantity
    return total

Функция для удаления элементов:

def eliminaritem(request, id):
if request.method == "POST":
    item = OrderItem.objects.get(product = id)
    item.delete()
    return render(request, "store/deletecartitem.html", {'item': item})

if  OrderItem.objects.all == None:
    customer = request.user.customer
    order = Order.objects.all(customer = customer)
    order.delete()

Первая часть этой функции работает, однако то, как я подошел ко второму IF, ужасно. Итак, в основном, когда нет ни одного OrderItems, заказ должен быть удален. Всякий раз, когда товар добавляется в корзину, заказ создается

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

from django.db.models import Q


class Order(models.Model):
    customer = models.ForeignKey(
        Customer, on_delete=models.SET_NULL, null=True, blank=True
    )
    date_ordered = models.DateTimeField(auto_now_add=True)
    complete = models.BooleanField(default=False)
    transaction_id = models.CharField(max_length=100, null=True)

    def __str__(self):
        return f'{self.id}'

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=('customer',),
                condition=Q(complete=False),
                name='incomplete_order_per_customer',
            )
        ]

Теперь что касается представления, представление может иметь побочные эффекты только в том случае, если метод является запросом POST, PUT, PATCH или DELETE. Ваш второй if не гарантирует этого, и поэтому не соответствует HTTP. Кроме того, ваше представление будет удалять OrderItem, если существует точно один такой элемент. Это означает, что если два пользователя имеют одинаковые OrderItem, то это приведет к ошибке, а если другой пользователь имеет такой OrderItem, то другой пользователь может сделать такой запрос, чтобы получить этот OrderItem удаленный

Вы можете определить OrderItem для вошедшего клиента и удалить его с помощью:

from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_http_methods


@login_required
@require_http_methods(['DELETE', 'POST'])
def eliminaritem(request, id):
    order_items = OrderItem.objects.filter(
        order__complete=False, order__customer__user=request.user
    )
    item = get_object_or_404(order_items, product_id=id)
    item.delete()
    if not order_items.exists():
        Order.objects.filter(
            customer__user=request.user, completed=False
        ).delete()
    return redirect('name-of-some-view')

Note: You can limit views to a view to authenticated users with the @login_required decorator [Django-doc].


Note: In case of a successful POST request, you should make a redirect [Django-doc] to implement the Post/Redirect/Get pattern [wiki]. This avoids that you make the same POST request when the user refreshes the browser.

Я предполагаю, что вы используете представление eliminaritem() для удаления элемента.

def eliminaritem(request, id):
    if request.method == "POST":
        item = OrderItem.objects.get(product = id)
        item.delete()
        return render(request, "store/deletecartitem.html", {'item': item})

    if  OrderItem.objects.all == None:
        customer = request.user.customer
        order = Order.objects.all(customer = customer)
        order.delete()

Проблема здесь в том, что OrderItem.objects.all() вернет все OrderItems всех заказов. До тех пор, пока где-то есть корзина с товаром, запрос никогда не будет пустым. Кроме того, поскольку вы возвращаетесь до того, как может быть выполнен второй if, код никогда не будет достигнут.

def eliminaritem(request, id):
    if request.method == "POST":
        item = OrderItem.objects.get(product = id)

        # First get the order behind the item.
        relevant_order = item.order

        # Check if order is from that user before deletion.
        if not relevant_order.customer == request.user
            # return some 403 error

        item.delete()

        # After deletion of the item check if there are items left.
        if not relevant_order.orderitem_set.all()
            relevant_order.delete()

        return render(request, "store/deletecartitem.html", {})

Я использовал ваш код, чтобы вы могли быстро внести изменения.

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