diff --git a/shop/migrations/0006_cart_cartitem.py b/shop/migrations/0006_cart_cartitem.py new file mode 100644 index 0000000..4bdaf8e --- /dev/null +++ b/shop/migrations/0006_cart_cartitem.py @@ -0,0 +1,90 @@ +# Generated by Django 5.1.3 on 2024-11-27 12:10 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("shop", "0005_productprice_price_with_tax"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Cart", + fields=[ + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + primary_key=True, + serialize=False, + verbose_name="uuid", + ), + ), + ( + "creation_date", + models.DateTimeField( + auto_now_add=True, verbose_name="fecha de creación" + ), + ), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="usuario", + ), + ), + ], + options={ + "verbose_name": "carrito", + "verbose_name_plural": "carritos", + }, + ), + migrations.CreateModel( + name="CartItem", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "quantity", + models.PositiveIntegerField(default=1, verbose_name="cantidad"), + ), + ( + "cart", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="items", + to="shop.cart", + verbose_name="carrito", + ), + ), + ( + "product", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="shop.product", + verbose_name="producto", + ), + ), + ], + options={ + "verbose_name": "línea de carrito", + "verbose_name_plural": "líneas de carrito", + }, + ), + ] diff --git a/shop/models.py b/shop/models.py index 533d109..9c9585d 100644 --- a/shop/models.py +++ b/shop/models.py @@ -6,6 +6,10 @@ from django.utils import timezone from django.utils.text import gettext_lazy as _ from django.utils.text import slugify +from django.contrib.auth import get_user_model + +User = get_user_model() + class TimestampedModel(models.Model): creation_date = models.DateTimeField( @@ -398,3 +402,38 @@ class Order(TimestampedModel): class Meta: verbose_name = _("pedido") verbose_name_plural = _("pedidos") + + +class Cart(models.Model): + uuid = models.UUIDField(default=uuid4, primary_key=True, verbose_name=_("uuid")) + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + verbose_name=_("usuario"), + blank=True, + null=True, + ) + creation_date = models.DateTimeField( + auto_now_add=True, verbose_name=_("fecha de creación") + ) + + class Meta: + verbose_name = _("carrito") + verbose_name_plural = _("carritos") + + +class CartItem(models.Model): + cart = models.ForeignKey( + "shop.Cart", + on_delete=models.CASCADE, + related_name="items", + verbose_name=_("carrito"), + ) + product = models.ForeignKey( + "shop.Product", on_delete=models.CASCADE, verbose_name=_("producto") + ) + quantity = models.PositiveIntegerField(default=1, verbose_name=_("cantidad")) + + class Meta: + verbose_name = _("línea de carrito") + verbose_name_plural = _("líneas de carrito") diff --git a/web/components/__init__.py b/web/components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/web/components/views.py b/web/components/views.py new file mode 100644 index 0000000..e7974fb --- /dev/null +++ b/web/components/views.py @@ -0,0 +1,35 @@ +from django.views.generic import TemplateView +from shop.filters import ProductFilter +from shop.models import Product +from web.mixins import FilteredQuerysetMixin, PaginatedQuerysetMixin, CartMixin + + +class ListProducts(TemplateView, FilteredQuerysetMixin, PaginatedQuerysetMixin): + template_name = "web/list_products.html" + queryset = Product.objects.all() + filter_class = ProductFilter + + def get_context_data(self, **kwargs): + qs = self.get_queryset() + page = self.get_paginated_queryset(qs) + + return { + "page": page, + "has_next_page": page.has_next(), + "has_previous_page": page.has_previous(), + } + + +class CartDropdown(TemplateView, CartMixin): + template_name = "components/cart/cart_navbar.html" + + def get_context_data(self, **kwargs): + cart = self.get_cart() + + return { + "cart": cart, + } + + +list_products = ListProducts.as_view() +cart_dropdown = CartDropdown.as_view() diff --git a/web/forms.py b/web/forms.py new file mode 100644 index 0000000..3bfdf87 --- /dev/null +++ b/web/forms.py @@ -0,0 +1,13 @@ +from django import forms +from django.forms import widgets + + +class CartItemForm(forms.Form): + """ + + + + """ + + product = forms.IntegerField(widget=widgets.HiddenInput) + quantity = forms.IntegerField() diff --git a/web/mixins.py b/web/mixins.py index f0b87a4..17b12d5 100644 --- a/web/mixins.py +++ b/web/mixins.py @@ -1,6 +1,9 @@ from django.conf import settings from django.core.paginator import Paginator +from shop.models import Cart +from web.settings import ANONYMOUS_CART_ID_COOKIE_NAME + class FilteredQuerysetMixin: queryset = None @@ -25,3 +28,13 @@ class PaginatedQuerysetMixin: page = self.request.GET.get("page", 1) qs = paginator.get_page(page) return qs + + +class CartMixin: + def get_cart(self): + if not self.request.user.is_authenticated: + uid = self.request.COOKIES.get(ANONYMOUS_CART_ID_COOKIE_NAME) + cart = Cart.objects.get(uuid=uid) + else: + cart = Cart.objects.filter(user=self.request.user).first() + return cart diff --git a/web/settings.py b/web/settings.py new file mode 100644 index 0000000..525f52f --- /dev/null +++ b/web/settings.py @@ -0,0 +1 @@ +ANONYMOUS_CART_ID_COOKIE_NAME = "caid" diff --git a/web/templates/components/cart/add_to_cart.html b/web/templates/components/cart/add_to_cart.html new file mode 100644 index 0000000..ecd27c8 --- /dev/null +++ b/web/templates/components/cart/add_to_cart.html @@ -0,0 +1,15 @@ +{% load i18n %} +
diff --git a/web/templates/components/cart/cart_dropdown.html b/web/templates/components/cart/cart_dropdown.html index 017f940..9e52769 100644 --- a/web/templates/components/cart/cart_dropdown.html +++ b/web/templates/components/cart/cart_dropdown.html @@ -1,35 +1,57 @@ {% load i18n %}$599
-Qty: 1
+ {% if cart.items.count == 0 %} +{{ cart_item.product.price.price_with_tax }}
{% translate 'Cantidad' %}: {{ cart_item.quantity }}
+ + + + +{{ product.price.price_with_tax }}€
-