Skip to content

Instantly share code, notes, and snippets.

@Tobi-De
Last active October 11, 2022 10:53
Show Gist options
  • Save Tobi-De/b973902cfd32bc9cf1a81424cba94bee to your computer and use it in GitHub Desktop.
Save Tobi-De/b973902cfd32bc9cf1a81424cba94bee to your computer and use it in GitHub Desktop.
This not explains the reason behind the get_price method needed by dj-shop-cart

Ok first of all, what is the get_price method ?

The get_price is a method required by the dj-shop-cart package that you must implement on your django model representing the products that you are adding to the cart. The signature is as follow:

class Product(models.Model):
      price = models.DecimalField(decimal_places=2, max_digits=10)
      
      def get_price(self, item):
          return self.price

The get_price method take in a CartItem instance and return back a python decimal value. In the example below the get_price nethod just returns your product price but it can do a lot mode depending on your use case.

why the get_price is needed ?

The main reason is for your cart to always have an updated version of the price of every product added to the cart. Let's take an example:

  1. User A visit your online shop
  2. They add an item to the cart, mulitple in fact, cause they quite like what your store is offering
  3. They are done with their shopping session and decide to proceed to checkout
  4. At the same time, you decide to offer a deal on some of your products, so their prices have changed (maybed you didn't lower the price directly, but have a special mechanis to apply deal) and it turns out that User A have in their cart one of the item that have changed price

I think you can see the issue at this point, if dj-shop-cart was getting the price in a static way, with an attribute priceon your model for example, it price will get an incorrect value because your custom logic to apply deals would be elsewhere, but with a method like get_price you can write custom logic to make sure your cart items alwas have an up to date price. The get_price method also get in parameter the CartItem instance for your products, so you can make computations based on the quantity or any other metadata you could have passed to your product while adding it to the cart.

I hope this make thing clear. If you don't really what to do, you can just copy paste the get_price in the code snippet abose, just return your product price.

I will update the documentation later with this explanation and please don't mind typos I made this in a hurry.

@hswIT
Copy link

hswIT commented Sep 7, 2022

Say, if I want to get another field in my Class model other than price, what should I add instead?
E.g. there are photos and product description associated with the products itself, how can I attach them along with the cart item under the cart?

class Product(models.Model):
description = models.TextField(blank=True)
price = models.FloatField(default=0)
photo_main = models.ImageField(upload_to='photos/%Y/%m/%d')

def get_photo(self, item):
      return self.photo_main

def get_description(self, item):
      return self.description

@Tobi-De
Copy link
Author

Tobi-De commented Sep 7, 2022

Say, if I want to get another field in my Class model other than price, what should I add instead? E.g. there are photos and product description associated with the products itself, how can I attach them along with the cart item under the cart?

class Product(models.Model): description = models.TextField(blank=True) price = models.FloatField(default=0) photo_main = models.ImageField(upload_to='photos/%Y/%m/%d')

def get_photo(self, item):
      return self.photo_main

def get_description(self, item):
      return self.description

Nope that's not the point, get_price is the only one use by dj-shop-cart and is only meant to return the price.

Read this, every item in the cart has a reference to the related product so you can just do

for item in cart:
	print(item.product.photo_main)

to access you product data.

@hswIT
Copy link

hswIT commented Sep 8, 2022

Thanks for advising. It takes me a big leap forward. However, there is still a final puzzle to be fixed. I tried to use the remove_product function in the cart.html. Details are as below. It didn't prompt me any errors but nothing got changed. The item of the cart is still there. Just wonder what is still wrong....

            <form action="{% url 'remove_product' item.product.id %}" method="POST">
              {% csrf_token %} 
              <label for="ID"></label>
              <input
                type="hidden"
                name="product"
                value="{{item.product.id}}"
              /><br />
              <button type="submit">Remove</button>
            </form> <!-- THIS IS the cart.html -->
            

            def remove_product(request, product_id):
                cart = Cart.new(request)
                product = get_object_or_404(Product.objects.all(), id=request.POST["product"])
                cart.remove(product)
                return redirect('carts')
                <!-- THIS IS Cart/views.py -->

               urlpatterns = [
                         path('', views.cart, name="carts"),
                         path('empty_cart', views.empty_cart, name="empty_cart"),
                         path('remove_product/<int:product_id>', views.remove_product, name="remove_product"),
               ]   <------- THIS IS Cart/urls.py -------->

Both of the add_product and empty_cart work but not for the remove_product. Have been figuring it out for a long time but no idea.
Please kindly help out how to put in the last puzzle. Thanks.

@Tobi-De
Copy link
Author

Tobi-De commented Sep 8, 2022

Thanks for advising. It takes me a big leap forward. However, there is still a final puzzle to be fixed. I tried to use the remove_product function in the cart.html. Details are as below. It didn't prompt me any errors but nothing got changed. The item of the cart is still there. Just wonder what is still wrong....

            <form action="{% url 'remove_product' item.product.id %}" method="POST">
              {% csrf_token %} 
              <label for="ID"></label>
              <input
                type="hidden"
                name="product"
                value="{{item.product.id}}"
              /><br />
              <button type="submit">Remove</button>
            </form> <!-- THIS IS the cart.html -->
            

            def remove_product(request, product_id):
                cart = Cart.new(request)
                product = get_object_or_404(Product.objects.all(), id=request.POST["product"])
                cart.remove(product)
                return redirect('carts')
                <!-- THIS IS Cart/views.py -->

               urlpatterns = [
                         path('', views.cart, name="carts"),
                         path('empty_cart', views.empty_cart, name="empty_cart"),
                         path('remove_product/<int:product_id>', views.remove_product, name="remove_product"),
               ]   <------- THIS IS Cart/urls.py -------->

Both of the add_product and empty_cart work but not for the remove_product. Have been figuring it out for a long time but no idea. Please kindly help out how to put in the last puzzle. Thanks.

I need to clean up the api a bit later, remove_product take the item (in the cart) id. Every cart item has an id, you need to use that, for example your view can look like something like this

 def remove_product(request, item_id):
    cart = Cart.new(request)
    cart.remove(item_id)
    return redirect('carts')

@hswIT
Copy link

hswIT commented Sep 8, 2022

If so, what about the cart.HTML and the urls.py would be like? I have tried with item_id or item.id in the corresponding field but it prompts me error. Could you please shed me some light about the configuration in the URLs.py and the cart.HTML respectively? Thanks

@Tobi-De
Copy link
Author

Tobi-De commented Sep 8, 2022

If so, what about the cart.HTML and the urls.py would be like? I have tried with item_id or item.id in the corresponding field but it prompts me error. Could you please shed me some light about the configuration in the URLs.py and the cart.HTML respectively? Thanks

# url.py
 path(
        "remove-line-item-hx/<str:item_id>/",
        views.remove_line_item_hx,
        name="remove_line_item_hx",
    ),

# views.py
def remove_line_item_hx(request: HttpRequest, item_id: str):
    Cart.new(request).remove(item_id)
	...
{% for item in cart %}
<form action="{% url "revenues:remove_line_item_hx" item.id %}">
{% csrf_token %}
<input value="Delete" type="submit">
</form>
{% endfor %}

@hswIT
Copy link

hswIT commented Sep 8, 2022

Finally, I made it with your advise. Bingo, I add the quantity portion back to the cart.html like below and it works.
So now the last puzzle was made. Great~~~ Appreciate for the help and advising.

             <form action="{% url 'remove_product' item.id %}" method="POST">
              {% csrf_token %} 
              <label for="ID"></label>
              <input
                type="hidden"
                name="item_id"
                value="{{item.id}}"
              /><br/>
              <label for="QTY"></label>
              <input
                type="hidden"
                name="quantity"
                value="{{item.quantity}}"
              />
              <button type="submit">Remove</button>
            </form>

@Tobi-De
Copy link
Author

Tobi-De commented Sep 8, 2022

Finally, I made it with your advise. Bingo, I add the quantity portion back to the cart.html like below and it works. So now the last puzzle was made. Great~~~ Appreciate for the help and advising.

             <form action="{% url 'remove_product' item.id %}" method="POST">
              {% csrf_token %} 
              <label for="ID"></label>
              <input
                type="hidden"
                name="item_id"
                value="{{item.id}}"
              /><br/>
              <label for="QTY"></label>
              <input
                type="hidden"
                name="quantity"
                value="{{item.quantity}}"
              />
              <button type="submit">Remove</button>
            </form>

Glad you made it.

@hswIT
Copy link

hswIT commented Oct 11, 2022 via email

@Tobi-De
Copy link
Author

Tobi-De commented Oct 11, 2022

t. I am a sort of beginner of python and would like to learn more, and I found that you are a developer of python. Would like to know where I can get to know more in this area....like community or forum, Hope one day I can contribute myself to the python community.

@hswIT
If you want to learn more about python, I suggest this series of tutorials.

Most importantly, don't spend too much time on tutorials, if you want to get good at python (or anything really) you need lots of practice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment