Why is the error' ValueError at /add_to_cart/printed-shirt/ Field 'id' expected a number but got 'Red'.' being thrown?

Viewed 110

I got this error and have no idea why this is coming

ValueError at /add_to_cart/printed-shirt/

Field 'id' expected a number but got 'Green'.

I'm trying to add variations to my product. So when I'm submitting, I'm printing the values the users are selecting by writing print(request.POST.getlist('variations', [])) and those are coming back as ['Red', 'Medium']. Now I was trying to see if the product matching these variations already exists in the cart. If it exists, then I would increase the quantity, and if it does not exist, then I would add a new item. The error is being thrown at the line

order_item_qs = order_item_qs.filter(

But my code doesn't seem to work. Can anyone please help me with this? Thanks in advance!

My views.py:

@login_required
def add_to_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    variations = request.POST.getlist('variations', [])
    print(variations)

    minimum_variation_count = Variation.objects.filter(item=item).count()
    if len(variations) < minimum_variation_count:
        messages.info(request, "Please specify the required variations.")


    order_item_qs = OrderItem.objects.filter(
        item=item,
        user= request.user,
        ordered=False,
    )

    for v in variations:
        order_item_qs = order_item_qs.filter(
            item_variations__exact=v
        )

    if order_item_qs.exists():
        order_item = order_item_qs.first()
        order_item.quantity += 1
        order_item.save()
    else:
        order_item = OrderItem.objects.create(
            item=item,
            user= request.user,
            ordered=False,
        )

        order_item.item_variations.add(*variations)
        order_item.save()

    order_qs = Order.objects.filter(user=request.user, ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        if not order.items.filter(item__id=order_item.id).exists():
            order.items.add(order_item) 
            messages.success(request, "Product added to cart.")
            return redirect("order-summary")
    else:
        ordered_date = timezone.now()
        order = Order.objects.create(user=request.user, ordered_date=ordered_date)
        order.items.add(order_item)
        messages.success(request, "Product added to cart.")
        return redirect("order-summary")
    return redirect("order-summary")

My models.py:

class Item(models.Model):
   title = models.CharField(max_length=120)
   price = models.FloatField()

class Variation(models.Model):
   item = models.ForeignKey(Item, on_delete=models.CASCADE)
   name = models.CharField(max_length=50) # size, color

class ItemVariation(models.Model):
   variation  = models.ForeignKey(Variation, on_delete=models.CASCADE)
   value = models.CharField(max_length=50) # small, medium large etc

class OrderItem(models.Model):
   user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
   item  = models.ForeignKey(Item, on_delete=models.CASCADE)
   item_variations = models.ManyToManyField(ItemVariation)
   quantity = models.IntegerField(default=1)
   ordered = models.BooleanField(default=False)

class Order(models.Model):
   user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
   ref_code = models.CharField(max_length=20)
   ordered = models.BooleanField(default=False)
   items = models.ManyToManyField(OrderItem)
   start_date = models.DateTimeField(auto_now_add= True)
   ordered_date = models.DateTimeField()

My order_summary.html (where I can increase quantity):

<a href="{% url 'remove-single-item-from-cart' order_item.item.slug %}" class="btn mr-2"><i class="fa fa-minus"></i></a>
{{ order_item.quantity }}<a href="{% url 'add-to-cart' order_item.item.slug %}" class="btn ml-2"><i class="fa fa-plus"></i></a>

My urls.py:

path('add_to_cart/<slug>/', orders_views.add_to_cart, name='add-to-cart'),
path('remove_from_cart/<slug>/', orders_views.remove_from_cart, name='remove-from-cart'),
1 Answers

It's hard to be certain without more information, so I'll ask some extra things:

  1. What Line is throwing the error?
  2. What is slug's value when the error is thrown? (didn't see url posted up top)
  3. What is OrderItem model

Original Answer:

That being said, I think the error is this line: order_item.item_variations.add(*variations). variations is, I believe, ['Green', ...]. I feel like it probably would be something like order_item.item_variations.add(item.variation_set.filter(item_variation__value=...).first().pk) with the current model setup. The reason I think this is because it doesn't look the value of ItemVariation is the primary_key which is what add takes as arguments (or instances)

Extra Explanation:

First, I think your check to see if the item is already in the cart is wrong:

order_item_qs = order_item_qs.filter(
            item_variations__exact=v
        )

should be:

order_item_qs = order_item_qs.filter(
            item_variations__value=v
        )

I changed it to check for the value which is where you'll find the strings you are comparing. The previous was checking id, I believe. I also removed __exact, but realize that __exact is implied in the fixed version.

Secondly, I believe that you are using .add()^ wrong for your RelatedManager (how you access your many-to-many field). According to your models, ItemVariation does not have a primary key set in the model. This means django will autogenerate one for you.^^ The auto-generated field will be an AutoField that is an int. This means in order to use OrderItem.item_variations.add() you either need to provide an ItemVariation instance or a primary key of ItemVariation.

Currently you are providing it with a bunch of strings. To fix this you will need to query ItemVariations to get the correct instance. I would recommend changing order_item.item_variations.add(*variations) to a multi-line approach:

item_variations_to_add = ItemVariations.objects.filter(
    variation__item=item,
    value__in=variations
).values_list('id', flat=True)
order_item.item_variations.add(*item_variations_to_add)

This should fix the error, though it does present a potential problem of what if the variations aren't in the database. That is another problem you should think about, but is outside the scope of this answer.

^RelatedManager.add() documentation: https://docs.djangoproject.com/en/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager.add

^^Automatic Primary Keys documentation: https://docs.djangoproject.com/en/dev/topics/db/models/#automatic-primary-key-fields

Related