Field 'id' expected a number but got '(string)

I'm creating a T-shirt shop with variants/colors. In adding to cart, I get the error: Field 'id' expected a number but got 'woodstock'. Woodstock is the name of the shirt, but I'm passing the cartid to the function. cartid is actually being used in the remove_from_cart function, but I'm not sure why the error is thrown when I push add to cart. Here's the cart model:

class Cart(models.Model):
    #user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
    total = models.DecimalField(max_digits=100, decimal_places=2, default=0.00)
    timestamp = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    active = models.BooleanField(default=True)

    def __str__(self):
        return "Cart id: %s" %(

class CartItem(models.Model):
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, null=True, blank=True)
    product = models.ForeignKey(Product,on_delete=models.CASCADE)
    variations = models.ManyToManyField(Variation, blank=True)
    quantity = models.IntegerField(default=1)
    line_total = models.DecimalField(default=10.99, max_digits=100, decimal_places=2)
    timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
            return str(

def view(request):
    print("viewing cart")
        the_id = request.session['cart_id']
        the_id = None
    if the_id:
        cart = Cart.objects.get(id=the_id)
        new_total = 0.00
        for item in cart.cartitem_set.all():
            line_total = float(item.product.price) * item.quantity
            new_total += line_total
        request.session['items_total'] = cart.cartitem_set.count() = new_total

        context = {"cart":cart}
        empty_message = "Your cart is empty, please keep shopping"
        context = {"empty": True, "empty_message": empty_message}

    template = "cart/view.html"
    return render(request, template, context)

def add_to_cart(request, slug):
    print("add_to_cart pressed")
        the_id = request.session['cart_id']
        #create cart id
        new_cart = Cart()
        request.session['cart_id'] =
        the_id =
    cart = Cart.objects.get(id=the_id)
        product = Product.objects.get(slug=slug)
    except Product.DoesNotExist:
    product_variations = []
    if request.method == 'POST':
        qty = request.POST['qty']
        for item in request.POST:
            key = item
            val = request.POST[key]
                v = Variation.objects.get(product=product, category__iexact=key, title__iexact=val)
        cart_item = CartItem.objects.create(cart=cart, product=product)
        if len(product_variations) > 0:
        cart_item.quantity = qty
        print("cart item added")

        return HttpResponseRedirect(reverse("carts:cart"))

    return HttpResponseRedirect(reverse("carts:cart"))

def remove_from_cart(request, id):
    print(id) #this is showing the item name, the reason it's not working. Either traced back to html view or
        the_id = request.session['cart_id']
        cart = Cart.objects.get(id=the_id)
        return HttpResponseRedirect(reverse("carts:cart"))
    cartitem = CartItem.objects.get(id=id)#error is traced to this line
    cartitem.cart = None
    return HttpResponseRedirect(reverse("carts:cart"))


{% block content %}
<div class="col-sm-8 offset-sm-2">
{% if empty %}
  <h1 style="text-align:center;">{{ empty_message }}</h1>
{% else %}

  <table class="table">
        <td>Total: {{ }}</td>
    {% for item in cart.cartitem_set.all %}
      <td>{{ item.product }}
        {% if item.variations.all %}
        {% for var in item.variations.all %}
        <li> {{ var.category|capfirst }} : {{ var.title|capfirst }}</li>
        {% endfor %}
        {% endif %}

      <td>{{ item.product.price }}</td>
      <td>{{ item.quantity }}</td>
      <td><a href='{% url "carts:remove_from_cart" %}'>Remove</a></td>
    {% endfor %}

{% endif %}
{% endblock %} for cart


urlpatterns =[
    path('cart/', views.view, name='cart'),
    path('cart/<id>/', views.remove_from_cart, name='remove_from_cart'),
    path('cart/<slug:slug>/', views.add_to_cart, name='add_to_cart'),


One suggestion in researching this problem was to delete migrations and run makemigrations/migrate, but that didn't work for me. Any other suggestions or why is passing the name and not the id?

Answers: 1

Answered by Iain Shelvington, Oct. 13, 2021, 7:59 a.m.

Your remove_from_cart url path matches paths like cart/<id>/ where id does not have a type so matches anything, the add_to_cart path uses cart/<slug:slug>/ but because any slug will also match id from the previous path this view will ever be used. You need to make these paths unique so that they never match the same path.

One way is to make id an integer so that slugs will not match it

path('cart/<int:id>/', views.remove_from_cart, name='remove_from_cart'),
path('cart/<slug:slug>/', views.add_to_cart, name='add_to_cart'),

The better way is to add prefixes to these paths so that they never clash

path('cart/remove/<int:id>/', views.remove_from_cart, name='remove_from_cart'),
path('cart/add/<slug:slug>/', views.add_to_cart, name='add_to_cart'),