Saturday 5 February 2011

Improving the Cart

Updating the Model

In my second update I will make some improvements to the shopping cart model, notably allowing multiple products to be added to the cart and fixing the remove() method so it actually works.

class Cart(object):
    """
    Shopping cart stores products in the session and persists to a database
    """
    # Stores the items
    __items = dict()

    # Constructor
    def __init__(self):
        # Get cartID from the session if it exists
        cartID = session.get('cartID', None)
        # If cartID is set then load an instance of the database model
        # populated with existing items
        if cartID:
            cart = CartModel()
            self.cartModel = cart.get(cartID)
        # If not then create a new instance and save self to the database
        # and set cartID in the session
        else:
            cart = CartModel(object=self, status=0)
            DBSession.add(cart)
            transaction.commit()
            session['cartID'] = cart.id
            self.cartModel = cart

    # Main methods
    def add(self, product, qty):
        # Save dictionary of product attributes
        items = dict({'id': product.id,
          'qty': qty,
          'description': product.name,
          'price': product.price})
        self.set_items(items)
        self.save()

    def remove(self, productID):
        # Remove an item
        items = self.get_items()
        if int(productID) in items:
            del items[int(productID)]

        self.save()

    def clear(self):
        # Clear items from session, but NOT database as we will need
        # a record of transactions
        session.delete()

    def save(self):
        # Persist changes
        session.save()
        self.cartModel.object = self
        transaction.commit()

    # Getters/Setters
    def set_items(self, items):
        self.__items[items['id']] = items
        session['items'] = self.__items

    def get_items(self):
        if session.get('items', None):
            self.__items = session['items']
        return self.__items


All I have done here is change the set_items() method to properly append the items dict to the self.__items dict. The remove method was puzzling to me coming from a background in PHP until I remembered that the keys in a Python dictionary can be any type (except another dictionary) and that the productID passed into it from the controller was a string and the key is an integer. In PHP this would not matter, but Python was throwing a KeyError, but explicitly casting productID to an integer solved this little issue.

Now the cart properly handles adding and removing products from it.

The Controller

I will briefly go over the controller functions in root.py. I think in my finished application I will move all cart related actions into a separate controller but for now when I am mainly just debugging my models I shall leave them in the root controller.

@expose()
    def add_to_cart(self, productID, quantity):
        # Get cart instance
        cart = self.get_cart()
        # create a new product object
        product = Product()
        # add product to cart
        cart.add(product.get(productID), quantity)
        # Feedback and redirect
        flash('Product added')
        redirect('/')

    @expose()
    def remove_from_cart(self, productID):
        # Get cart
        cart = self.get_cart()
        # Remove productID from cart
        cart.remove(productID)
        # Feedback and redirect
        flash('Product removed')
        redirect('/')

These are fairly self-explanatory, we simply call the instance of the cart add/remove and then set a flash message and redirect back to the home page.

In my next update I will bring in an address model and start creating some checkout logic so that the cart can do something useful.

No comments:

Post a Comment