0

Edit:

My goal is to create a small e-commerce. In my index I have a list of products, one of the attributes is a boolean called in_cart which states if the product is in the cart or not. By default all boolean values are false. In my template is a table with all the products next to which I put a button "add to cart", which redirects to the cart template. However when I click on add to cart, the value of the boolean in question does not change to true. Any thoughts?

    <table>
    <tr>
        <th>List of car parts available:</th>
    </tr>
    <tr>
        <th>Name</th>
        <th>Price</th>
    </tr>
    {% for product in products_list %}
    <tr>
      <td>{{ product.id }}</td>
      <td>{{ product.name }}</td>
      <td>${{ product.price }}</td>
      <td>{% if not product.in_cart %}
              <form action="{% url 'add_to_cart' product_id=product.id %}" method="POST">
                {% csrf_token %}
                <input type="submit" id="{{ button_id }}" value="Add to cart">
              </form>
          {% else %}
              {{ print }}
          {% endif %}
      </td>
    </tr>
    {% endfor %}
  </table>

  <a href="{% url 'cart' %}">See cart</a>

And these are my views:

def index(request):
    if request.method == "GET":
        products_list = Product.objects.all()
        template = loader.get_template('products/index.html')
        context = {'products_list': products_list}
        return HttpResponse(template.render(context, request))
    return HttpResponse('Method not allowed', status=405)


def cart(request):
    cart_list = Product.objects.filter(in_cart = True)
    template_cart = loader.get_template('cart/cart.html')
    context = {'cart_list': cart_list}
    return HttpResponse(template_cart.render(context, request))


def add_to_cart(request, product_id):
    if request.method == 'POST':
        try:
            product = Product.objects.get(pk=product_id)
            product.in_cart = True
            product.save()
        except Product.DoesNotExist:
            return HttpResponse('Product not found', status=404)
        except Exception:
            return HttpResponse('Internal Error', status=500)
    return HttpResponse('Method not allowed', status=405)

Model:

class Product(models.Model):
    name = models.CharField(max_length=200)
    price = models.IntegerField()
    in_cart = models.BooleanField(default=False)
    ordered = models.BooleanField(default=False)
    def __str__(self):
        return self.name

URLs

urlpatterns = [
    path('', views.index, name='index'),
    path('cart/', views.cart, name='cart')
    re_path(r'^add_to_cart/(?P<product_id>[0-9]+)$', views.add_to_cart, name='add_to_cart')
]

Error in my terminal

File "/Users/Nicolas/code/nicobarakat/labelachallenge/products/urls.py", line 8
    re_path(r'^add_to_cart/(?P<product_id>[0-9]+)$', views.add_to_cart, name='add_to_cart')
          ^
SyntaxError: invalid syntax

This is what it looks like in localhost: index

NicoBar
  • 555
  • 1
  • 7
  • 16
  • You can't do it because after template renders, django has no access to change anything. You can use javascript instead and handle that functionality with it. – Mr Alihoseiny Jun 23 '18 at 09:17
  • I just tried to use a form submit button in my html with a POST request, then in my view say if if request.method == 'POST', then product.in_cart = True. Should work no? – NicoBar Jun 23 '18 at 11:11
  • Yes. It will work but didn't change the template without regenerating it. I think your question is not clear. If you edit it and add all things you want and all the relative information, probably I can help you. But now it is not clear what you really want. – Mr Alihoseiny Jun 23 '18 at 13:56
  • Just added more info, thanks :) – NicoBar Jun 23 '18 at 18:31
  • It will not work any way! Since you have to have CARD model, and then, on user logging in you have to create card according to session, or by logged in user. Then you have to create ne record CARD_ITEMS wich will be based on PRODUCT model. But now after successful saving of the product, you will have THSI PRODUCT for ALL users be in card. – ilyas Jumadurdyew Jun 24 '18 at 16:06

1 Answers1

1

First of all, your if statement is not reachable. Because you had a return before it. When you call return in a function, the next lines of function those are after the return will not execute.

So you should change the index function. Also, you should send an identifier of the product with your post request. Identifier could be the id or any other unique field in your model.

So your code should be something like this:

def index(request):
    if request.method == 'POST': # Request is post and you want to update a product.
        try:
            product = Product.objects.get(unique_field=request.POST.get("identifier")) # You should chnage `unique_field` with your unique filed name in the model and change `identifier` with the product identifier name in your form.
            product.in_cart = True
            product.save()
            return HttpResponse('', status=200)
        except Product.DoesNotExist: # There is no product with that identifier in your database. So a 404 response should return.
            return HttpResponse('Product not found', status=404)
        except Exception: # Other exceptions happened while you trying saving your model. you can add mor specific exception handeling codes here.
            return HttpResponse('Internal Error', status=500)
    elif request.method == "GET": # Request is get and you want to render template.
        products_list = Product.objects.all()
        template = loader.get_template('products/index.html')
        context = {'products_list': products_list}
        return HttpResponse(template.render(context, request))
    return HttpResponse('Method not allowed', status=405) # Request is not POST or GET, So we should not allow it.

I added all information you need in the comments of the code. I think you should spend more time on python and django documents. But if you still have any questions, you can ask in comments. After question edit If you don't want to use a readonly field in your form, you should make two changes in your code. First of all, you should add a url with product_id parameter in your urls.py file. Something like this:

url(r'^add_to_cart/(?P<product_id>[0-9]+)$', 'add_to_cart_view', name='add_to_cart')

Then you should add separate your add_to_cart view from index view. Your views should be like this:

def index(request): 
    if request.method == "GET":
        products_list = Product.objects.all()
        template = loader.get_template('products/index.html')
        context = {'products_list': products_list}
        return HttpResponse(template.render(context, request))
    return HttpResponse('Method not allowed', status=405)


def cart(request):
    cart_list = Product.objects.filter(in_cart = True)
    template_cart = loader.get_template('cart/cart.html')
    context = {'cart_list': cart_list}
    return HttpResponse(template_cart.render(context, request))


def add_to_cart(request, product_id):
    if request.method == 'POST':
        try:
            product = Product.objects.get(pk=product_id)
            product.in_cart = True
            product.save()
            return HttpResponse('', status=200)
        except Product.DoesNotExist:
            return HttpResponse('Product not found', status=404)
        except Exception:
            return HttpResponse('Internal Error', status=500)
    return HttpResponse('Method not allowed', status=405)

Now you should change the action link of your form to this:

{% url 'add_to_cart' product_id=product.id %}
Mr Alihoseiny
  • 1,202
  • 14
  • 24
  • Thank you so much!! So I guess I can do this without jQuery it's great. I changed unique field to "in_cart" and identifier to "buttonID". Doesn't work, is that what you meant? (Just edited my first post so you can see the updated table) – NicoBar Jun 24 '18 at 12:05
  • No. you should replace `unique_field` with product ID. The `identifier` is a field in your form with value equal to id of the product. for example, if you want add a product with id = 5 to cart, you should have a readonly field to your form. If you can not do it, please add the template and models code to your question. If you can do it right, you can select this answer as correct answer. – Mr Alihoseiny Jun 24 '18 at 16:26
  • I heard it is a bad idea to have readonly fields. Isn't there any other way? Just modified the index and table maybe you can have a look. – NicoBar Jun 24 '18 at 21:41
  • Thank you makes sense! I get a syntax error with the url statement. – NicoBar Jun 25 '18 at 10:15
  • It's probably because the view part of it. You should replace that part with the correct path to your view in your project. I just left a sample for your. – Mr Alihoseiny Jun 26 '18 at 04:48
  • Just modified the code as you said, but it still gives me invalid syntax – NicoBar Jul 09 '18 at 14:11
  • Please write your error code and add your new code to the question. – Mr Alihoseiny Jul 09 '18 at 15:42
  • Done. This is the latest version of what I have in my editor – NicoBar Jul 09 '18 at 16:23
  • My terminal tell me the there is a syntax error at this line re_path(r'^add_to_cart/(?P[0-9]+)$', views.add_to_cart, name='add_to_cart') – NicoBar Jul 10 '18 at 14:24
  • Ok it works!! I just updated the code. Now when I click on add to cart it actually changes the boolean value. However it redirects me to a page where it is written Method not allowed. – NicoBar Jul 10 '18 at 21:28
  • I missed return statement in first try block in `add_to_cart` function. I added it for you. And for avoiding redirecting, you can use solutions in this [answer](https://stackoverflow.com/questions/19454310/stop-form-refreshing-page-on-submit). – Mr Alihoseiny Jul 11 '18 at 06:29