/ok-cart

Django cart.

Primary LanguagePythonMIT LicenseMIT

django-ok-cart PyPI version

Build status Code health Python versions PyPI downloads Software license Project Status

Django Cart.

Installation

Install with pip:

$ pip install django-ok-cart djangorestframework

Update INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    'ok_cart',
    'rest_framework',
    ...
]

Apply migrations:

python manage.py migrate

Available settings

CART_ADD_PIPELINES - Functions to run after adding each passed item to the cart.

# settings.py

CART_ADD_PIPELINES = (
   'apps.store.contrib.cart.pipelines.save_shop_id_to_cart_parameters',
)

# apps.store.contrib.cart.pipelines.py

def save_shop_id_to_cart_parameters(
        cart: 'Cart',
        user: 'User',
        content_object: 'Model',
        cart_item: 'CartItem',
        cart_group: 'CartGroup',
        **kwargs
):
    if isinstance(content_object, Product) and cart_group:
        cart_group.parameters['shop_id'] = content_object.shop_id
        cart_group.save(update_fields=['parameters'])
        cart_item.parameters['shop_id'] = content_object.shop_id
        cart_item.save(update_fields=['parameters'])

CART_POST_ADD_PIPELINES - Functions to run after adding all passed items to the cart.

Note: To save cart items prices you need to implement your custom pipeline like in example below.

# settings.py

CART_POST_ADD_PIPELINES = (
   'apps.store.contrib.cart.pipelines.apply_product_prices_to_cart',
)

# apps.store.contrib.cart.pipelines.py

from ok_cart.selectors import get_cart_items_by_cart
from apps.store.models import Product
from apps.store.selectors import get_product_price
from shared.utils import get_content_type

def get_product_cart_items(
        *,
        cart: 'Cart',
        with_related: bool = True
) -> 'QuerySet':
    cart_items = (
        get_cart_items_by_cart(
            cart=cart,
            with_related=with_related
        )
        .filter(
            content_type=get_content_type(Product)
        )
    )

    return cart_items

def get_cart_item_price(
        *,
        content_object: 'Model',
        user: 'User',
        cart: 'Cart',
        **kwargs
) -> Decimal:
    """
    Return price for specific type of object
    """
    price = None

    if isinstance(content_object, Product):
        price = get_product_price(product=content_object)

    return price

def apply_product_prices_to_cart(
        *,
        cart: 'Cart',
        user: 'User',
        **kwargs
):
    cart_items = (
        get_product_cart_items(
            cart=cart,
            with_related=False
        )
    )

    for cart_item in cart_items:
        price = (
            get_cart_item_price(
                content_object=cart_item.content_object,
                user=user,
                cart=cart,
            )
        )
        cart_item.price = price
        cart_item.save()

CART_ELEMENT_REPRESENTATION_SERIALIZERS - Serializers to represent cart items objects.

# settings.py

CART_ELEMENT_REPRESENTATION_SERIALIZERS = {
    'store.Product': 'api.rest.store.serializers.product.retrieve.ProductCartRetrieveSerializer',
}

CART_ELEMENT_ALLOWED_TYPES - Tuple of tuples of cart items allowed types.

# settings.py

CART_ELEMENT_ALLOWED_TYPES = (
    ('store', 'product'),
)

CART_PRICE_PROCESSOR - Function to modify cart prices, like converting to another currency.

# settings.py

CART_PRICE_PROCESSOR = 'apps.store.contrib.cart.cart_price_processor'

# apps.store.contrib.cart.price.py

def cart_price_processor(
        *,
        request,
        price
):
    return price

CART_BASE_API_VIEW - Base API View for your cart views.

# settings.py

CART_BASE_API_VIEW = 'apps.store.contrib.cart.StandardsMixin'

CART_GETTER - Function to get or create cart. ok_cart.selectors.get_cart_from_request by default.

# settings.py

CART_GETTER = 'apps.store.contrib.cart.selectors.cart_getter'

# store.contrib.cart.selectors.py

def cart_getter(
        *,
        request: 'HttpRequest',
        cart_queryset: 'QuerySet' = Cart.objects.open().optimized(),
        auto_create: bool = True
) -> 'Cart':
    pass

CART_MERGE_ENABLED - Setting to enable carts merge during login/logout flow. To make it work properly, add this setting:

# settings.py

SESSION_ENGINE = 'ok_cart.session_store'

Quickstart

To enable cart views, add next URL patterns:

urlpatterns = [
    ...
    path('', include('ok_cart.api.urls')),
]

Endpoints

  1. /api/v1/cart/change/ - API View to add items to cart. type value is a structure like app_label.model_name.

Possible payload:

{
    "entities": [
        {
            "element": {
                "id":"9619f790-9a02-4ac3-ad34-22e4da3a6d54",
                "type":"store.product"
            },
            "quantity":"1"
        }
    ]
}
  1. /api/v1/cart/clear/ - API View to remove all items from cart.
  2. /api/v1/cart/quantity/ - API View to get cart's quantity and total price.

Possible result:

{
    "quantity": 3,
    "total_price": 750
}
  1. /api/v1/cart/retrieve/ - API View to retrieve cart data.

Possible result:

{
    "groups": [
        {
            "id": 34,
            "price": 750,
            "base": {
                "element": {
                    "id": "9619f790-9a02-4ac3-ad34-22e4da3a6d54",
                    "caption": "Ноутбук",
                    "type": "store.product",
                    "props": {
                        "title": "Ноутбук",
                        "short_description": "Ноут для чайников",
                        "category": {
                            "id": 1,
                            "caption": "Ноутбуки и компьютеры",
                            "type": "store.category",
                            "props": {
                                "id": 1,
                                "label": "noutbuk-komp",
                                "title": "Ноутбуки и компьютеры",
                                "parent": null,
                                "depth": 0
                            }
                        },
                        "image": {},
                        "shop": null,
                        "shop_identifier": "",
                        "price": 250,
                        "old_price": null,
                        "url": "/product/noutbuk-0c4qoewu-vxmong1s/"
                    }
                },
                "quantity": 3,
                "price": 250,
                "parameters": {
                    "shop_id": null
                }
            },
            "relations": [],
            "parameters": {
                "shop_id": null
            }
        }
    ],
    "quantity": 3,
    "total_price": 750,
    "parameters": {}
}