0

I am trying to achieve an order system for an e-commerce site with Django. I have Order Model and OrderItem Model as such

class OrderItem(models.Model):
    product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
    is_ordered = models.BooleanField(default=False)
    owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    date_added = models.DateTimeField(auto_now=True)
    date_ordered = models.DateTimeField(null = True)

    def __str__(self):
        return self.product.name

class Order(models.Model):
    ref_code = models.UUIDField(default=uuid.uuid4, editable=False)
    items = models.ManyToManyField(OrderItem)
    owner = models.ForeignKey(Profile, on_delete=models.SET_NULL, null=True)
    is_ordered = models.BooleanField(default=True)
    date_ordered = models.DateTimeField(auto_now=True)
    shipping = models.ForeignKey(AddressAndInfo, on_delete=models.SET_NULL, null=True)
    is_shipped = models.BooleanField(default=False)
    price = models.FloatField(default=0.0)

And My view function is such:

def checkout(request):
order_items = OrderItem.objects.filter(
    owner=request.user).filter(is_ordered=False).all()

address = AddressAndInfo.objects.filter(user=request.user).get()
if(order_items.count() > 0):
    total = 0
    for item in OrderItem.objects.filter(owner=request.user).filter(is_ordered=False).all():
        if item.product.discounted_price > 0:
            total = total + item.product.discounted_price
        else:
            total = total + item.product.price
    order = Order.objects.create(
        owner = Profile.objects.get(user= request.user.id),
        shipping = address,
        price = total
    )
    new = Order.objects.get(items = None)
    print(new.ref_code)
    new.items.add(OrderItem.objects.get(owner=request.user, is_ordered=False))
    for item in order_items:
        item.is_ordered = True
        item.save()
    return redirect('dash')
else:
    messages.success(request, 'No item in Cart')
    return redirect('index')

Now the problem here is that when I try to add the second order from the user it adds order-item from the second order to all the existing order and. The result is that all the orders have same order-items. when ever I try to add order new order the order-item from the new order gets added to all existing orders.

Jamilur Rahman
  • 69
  • 2
  • 12

1 Answers1

0

I made small changes to your code with some comments, hope this can help! :)

def checkout(request):
    order_items = OrderItem.objects.filter(owner=request.user, is_ordered=False).all()

    address = AddressAndInfo.objects.filter(user=request.user).get()
    if(order_items.count() > 0):
        total = 0
        # Look, you can reuse order_items here instead of making another query to the database :)
        for item in order_items:
            if item.product.discounted_price > 0:
                total = total + item.product.discounted_price
            else:
                total = total + item.product.price

        order = Order.objects.create(
            owner = Profile.objects.get(user= request.user.id),
            shipping = address,
            price = total
        )
        # I think you were making a request to the database to get the Order that has no items, 
        # are you sure it will be always be just one order?
        # Anyway that wouldn't be necessary if you already have the instance of the recently created order in the 'order' variable above
        # new = Order.objects.get(items = None)
        print(order.ref_code)

        # Just one item is being added to the recently created Order here, 
        # and another query is being made to the database to get just one OrderItem with (owner=request.user, is_ordered=False)
        # maybe the is_ordered value of the item would be modified after this but I think it's safer to add the item after changing that value
        # order.items.add(OrderItem.objects.get(owner=request.user, is_ordered=False))
        for item in order_items:
            item.is_ordered = True            
            item.save()
            # Instead each item should be added inside this loop after each one is modified and saved
            order.items.add(item)
        return redirect('dash')
    else:
        messages.success(request, 'No item in Cart')
        return redirect('index')

Hope this can help! Anyway I'm not sure if you should use the items = models.ManyToManyField(OrderItem) in the Order class, because you're saying that a same ItemOrder could belong to many Orders too? and I think what you want to do is that an OrderItem could only belong to just one Order right? maybe you can add an 'order' ForeignKey column to your OrderItem like this:

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, related_name='items')
    is_ordered = models.BooleanField(default=False)
    owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    date_added = models.DateTimeField(auto_now=True)
    date_ordered = models.DateTimeField(null = True)    

    def __str__(self):
        return self.product.name


class Order(models.Model):
    ref_code = models.UUIDField(default=uuid.uuid4, editable=False)
    owner = models.ForeignKey(Profile, on_delete=models.SET_NULL, null=True)
    is_ordered = models.BooleanField(default=True)
    date_ordered = models.DateTimeField(auto_now=True)
    shipping = models.ForeignKey(AddressAndInfo, on_delete=models.SET_NULL, null=True)
    is_shipped = models.BooleanField(default=False)
    price = models.FloatField(default=0.0)

If you do this all that you have to change is to assign the order to your OrderItems in the final loop where you were updating them

for item in order_items:
    item.is_ordered = True 
    item.order = order          
    item.save()

Now you have OrderItems with just one Order in a database level :)

Amir Afianian
  • 2,679
  • 4
  • 22
  • 46
marcelob33
  • 66
  • 4
  • But i was trying to set only the order items in the cart to order model. My code used to add items in the cart to all existing records. – Jamilur Rahman Oct 25 '20 at 05:34
  • On the other this code just adds one order with order items. My app requires that user can order multiple item in one order – Jamilur Rahman Oct 25 '20 at 05:35
  • Have you tried the changes and it keeps giving errors with the first piece of code? You get Orders with multiple OrderItems with the second piece of code that I added, maybe it seems that only add one order with order items, but that's the way you get One-To-Many relationships between models. – marcelob33 Oct 25 '20 at 15:35
  • You get Orders with multiple OrderItems with the second piece of code that I added, but that's the way you get One-To-Many relationships between models in Django, look at these links, they could help you to understand better what I was trying to do: [link](https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_one/) [link](https://stackoverflow.com/questions/6928692/how-to-express-a-one-to-many-relationship-in-django) – marcelob33 Oct 25 '20 at 15:37