Take all the items in the cart and put them in the orders

I am working on ecom, I have trouble on the code.
the trouble is that when the user makes an order it should take all the items in the cart, but in my case, it takes only the first item and leave the rest unregisters to order.

models:

class Order(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    email = models.EmailField()
    address = models.CharField(max_length=250)
    city = models.CharField(max_length=100)
    created = models.DateTimeField(auto_now_add=True)
    update = models.DateTimeField(auto_now=True)
    paid = models.BooleanField(default=False)
        class Meta:
            ordering = ('-created',)

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

        def get_total_cost(self):
            return sum(meal.get_cost() for meal in self.meals.all())


    class OrderItem(models.Model):
        order = models.ForeignKey(Order,
                                  related_name='items',
                                  on_delete=models.CASCADE)
        item = models.ForeignKey(Item,
                                 related_name='order_items',
                                 on_delete=models.CASCADE)
        price = models.DecimalField(max_digits=10, decimal_places=2)
        quantity = models.PositiveIntegerField(default=1)

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

        def get_cost(self):
            return self.price * self.quantity

views:

    def order_create(request):
        cart = Cart(request)
        if request.method == 'POST':
            form = OrderCreateForm(request.POST)
            if form.is_valid():
                order = form.save()
                for meals in cart:
                    OrderItem.objects.create(order=order,
                                             item=meals['item'],
                                             price=meals['price'],
                                             quantity=meals['quantity'])
                    # clear  the cart(table)
                    cart.clear()
                    return render(request,
                                  'orders/created.html',
                                  {'order': order})
        else:
            form = OrderCreateForm()
        return render(request,
                      'orders/create.html',
                      {'cart': cart, 'form': form})

how can fix it :frowning:

I think we’re probably going to need to see the OrderCreateForm that you’re using for this. (Are you using formsets here? If so, we’ll need to see your code using them.) We’re also going to need to see the Cart object. (We might also need to see the create.html template, but I’m not sure about that yet.) Finally, is this the complete view, or are there parts of this you’ve edited out?

this is the OrderCreateForm that I use:

class OrderCreateForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = ['first_name', 'last_name', 'email', 'address', 'city']

and this is the cart object:

class Cart(object):

    def __init__(self, request):
        """
        Initialize the cart(table).
        :param request:
        """
        self.session = request.session
        cart = self.session.get(settings.CART_SESSION_ID)
        if not cart:
            # save an empty cart(table) in the session
            cart = self.session[settings.CART_SESSION_ID] = {}
        self.cart = cart

    def add(self, item, quantity=1, override_quantity=False):
        """
        Add an item to the cart(table) or update its quantity.
        :param item:
        :param quantity:
        :param override_quantity:
        :return:
        """
        item_id = str(item.id)
        if item_id not in self.cart:
            self.cart[item_id] = {'quantity': 0,
                                  'price': str(item.price)}
        if override_quantity:
            self.cart[item_id]['quantity'] = quantity
        else:
            self.cart[item_id]['quantity'] += quantity
        self.save()

    def save(self):
        # mark the session as "modified" to make sure it get saved
        self.session.modified = True

    def remove(self, item):
        """
        Remove an item from the cart(table).
        :param item:
        :return:
        """
        item_id = str(item.id)
        if item_id in self.cart:
            del self.cart[item_id]
            self.save()

    def __iter__(self):
        """
        Iterate through all the items in the cart(table),
        the get the items for the database.
        :return:
        """
        item_ids = self.cart.keys()
        # get the items and add them to the cart(table)
        items = Item.objects.filter(id__in=item_ids)

        cart = self.cart.copy()
        for item in items:
            cart[str(item.id)]['item'] = item

        for meal in cart.values():
            meal['price'] = Decimal(meal['price'])
            meal['total_price'] = meal['price'] * meal['quantity']
            yield meal

    def __len__(self):
        """
        count all items in the cart.
        :return:
        """
        return sum(meal['quantity'] for meal in self.cart.values())

    def get_total_price(self):
        return sum(Decimal(meal['price']) * meal['quantity'] for meal in self.cart.values())

    def clear(self):
        # remove cart(table) from session
        del self.session[settings.CART_SESSION_ID]
        self.save()

this is the template create.html:

{ % extends “base.html” %}

{% load static %}

{% load tailwind_filters %}

{% block title %}

Checkout

{% endblock %}

{% block content %}

<h1>Checkout</h1>

<div class="order-info">

<h3>Your order</h3>

<ul>

{% for meal in cart %}

<li>

{{ meal.quantity }}x {{ meal.item.name }}

<span>${{ meal.total_price }}</span>

</li>

{% endfor %}

</ul>

<p>Total: ${{ cart.get_total_price }}</p>

</div>

<form method="post" class="order-form">

{{ form|crispy}}

<p><input type="submit" value="Place order"></p>

{% csrf_token %}

</form>

{% endblock %}

It looks like you may have an indentation error here. You’ve got your cart.clear and return render lines inside your for meals in cart loop. This is going to clear the cart and return after the first meals is processed. The rest of the meals aren’t going to be processed.

1 Like

thank you so much, I’ve been looking in and out of the code, and I can’t figure it out. you really helped me.