V
V
Vadim2020-02-18 17:39:57
Django
Vadim, 2020-02-18 17:39:57

How to properly display products on the shopping cart page?

I am learning Django. How to correctly display products from different categories on the shopping cart page if there are products with the same ID in different categories? For example, in the category "laptops" there is a product with id=5, and in the category "phones" there is a product with id=5. So, when adding a product to the cart and passing variables to the template, the page displays not only the product that was added to the cart, but also the product from another category with the same id.
Question: how to display laptops on the page if there are only laptops in the basket, phones, if there are only phones in the basket and all together.

Models

from django.db import models
from django.urls import reverse

class Note_Manufacturer(models.Model):
    name = models.CharField(verbose_name='Производитель', max_length=50,
                            blank=True, null=True)
    country = models.CharField(verbose_name='Страна', max_length=50,
                               blank=True, null=True)

    def __str__(self):
        return (str(self.name))

    def note_manufacturer(self):
        return reverse('note_manufacturer_detail', args=[str(self.pk)])


class Notebook(models.Model):
    brand = models.ForeignKey(Note_Manufacturer, verbose_name='Производитель',
                              related_name='notebook_list',
                              max_length=20,
                              on_delete=models.CASCADE, null=True)
    name = models.CharField(verbose_name='Модель', max_length=50,
                            blank=True, null=True, unique=True)
    color = models.CharField(verbose_name='Цвет', max_length=50,
                             blank=True, null=True)
    style = models.CharField(verbose_name='Категория', max_length=50,
                             blank=True, null=True)
    price = models.DecimalField(verbose_name='Цена', max_digits=10,
                                decimal_places=2, null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('note_product_detail', args=[str(self.pk)])


class Phone_Manufacturer(models.Model):
    name = models.CharField(verbose_name='Производитель', max_length=50,
                            blank=True, null=True)
    country = models.CharField(verbose_name='Страна', max_length=50,
                               blank=True, null=True)

    def __str__(self):
        return (str(self.name))

    def phone_manufacturer(self):
        return reverse('phone_manufacturer_detail', args=[str(self.pk)])


class Phone(models.Model):
    brand = models.ForeignKey(Phone_Manufacturer, verbose_name='Производитель',
                              related_name='phone_list',
                              max_length=20,
                              on_delete=models.CASCADE, null=True)
    name = models.CharField(verbose_name='Модель', max_length=50,
                            blank=True, null=True, unique=True)
    color = models.CharField(verbose_name='Цвет', max_length=50,
                             blank=True, null=True)
    style = models.CharField(verbose_name='Категория', max_length=50,
                             blank=True, null=True)
    price = models.DecimalField(verbose_name='Цена', max_digits=10,
                                decimal_places=2, null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('phone_product_detail', args=[str(self.pk)])


views/cart_detail
from django.shortcuts import render, redirect, get_object_or_404
from .cart import Cart
from .forms import CartAddForm
from my_first_site.note.models import Notebook
from my_first_site.phone.models import Phone
from orders.models import OrderItem
import itertools

def cart_detail(request):
    cart = Cart(request)           
    for item in cart:
            item['update_quantity_form'] = CartAddForm(
                initial={'quantity': item['quantity'], 'update': True})
    return render(request, 'cart_detail.html',
    {
        'cart': cart,
    })


cart.py
from decimal import Decimal
from django.conf import settings
from my_first_site.note.models import Notebook
from my_first_site.phone.models import Phone


class Cart(object):
    def __init__(self, request):
        # получаем объект сессии
        self.session = request.session
        # определяем сессию и называем ее cart
        cart = self.session.get(settings.CART_SESSION_ID)
        if not cart:
            # сохраняем корзину в сессию
            cart = self.session[settings.CART_SESSION_ID] = {}
        self.cart = cart

    def add(self, product, quantity=1, update_quantity=False):
        # преобразуем id товара в строку чтобы использовать JSON
        product_id = str(product.id)
        if product_id not in self.cart:
            # если товара нет в корзине,
            # создаем словарь с количеством товаров - 0, и ценой преобразованной в строку
            self.cart[product_id] = {
                'quantity': 0, 'price': str(product.price)}
            # обновляем количество товара в корзине
        if update_quantity:
            self.cart[product_id]['quantity'] = quantity
        else:
            # увеличиваем кол-во товаров в корзине
            self.cart[product_id]['quantity'] += quantity
        self.save()

    def save(self):
        # обновление сессии cart
        self.session[settings.CART_SESSION_ID] = self.cart
        # указываем что сессия изменена
        self.session.modified = True

    def remove(self, product):
        # получаем id товара
        product_id = str(product.id)
        if product_id in self.cart:
            self.cart[product_id]['quantity'] -= 1
        if self.cart[product_id]['quantity'] <= 1:
            # если товар в корзине, то удалить
            del self.cart[product_id]
        self.save()

    def __iter__(self):
        # перебор элементов корзины и получение их из базы данных
        product_ids = self.cart.keys()
        # получение объекта товара и добавление его в корзину
        notes = Notebook.objects.filter(id__in=product_ids)
        phones = Phone.objects.filter(id__in=product_ids)
        for note in notes:
            self.cart[str(note.id)]['note'] = note
        for phone in phones:
            self.cart[str(phone.id)]['phone'] = phone

        for item in self.cart.values():
            item['price'] = Decimal(item['price'])
            item['total_price'] = item['price'] * item['quantity']
            yield item

    def __len__(self):
        # подсчет всех товаров в корзине
        return sum(item['quantity'] for item in self.cart.values())

    def get_total_price(self):
        # подсчет стоимости товаров в корзине
        return sum(Decimal(
            item['price']) * item['quantity']
            for item in self.cart.values())

    def clear(self):
        del self.session[settings.CART_SESSION_ID]
        self.session.modified = True


cart_detail.html
{% extends 'index.html' %}
{% load crispy_forms_tags %}
{% load static %}

{% block title %}
<title>Корзина</title>
{% endblock %}


{% block content%}
<h2>Корзина</h2>
{% if user.is_authenticated %}
<h2><a href="{% url 'order_create' %}">Оформить заказ</a></h2>
<div class="cart_products">
    {% if cart|length > 0 %}
    {% for item in cart %}
    <div class="cart_product_item">
        {% if item.note.pk  %}
        <div class="item_name">
            <h3>Товар: {{ item.note.brand }} {{ item.note.name }}</h3>
        </div>
        <div class="item_body">
            <p>
                Идентификатор: {{ item.note.pk }}
            </p>
            <p>
                Цена: {{ item.note.price }}
            </p>
            <p>
                Количество: {{ item.quantity }} | Сумма: {{ item.total_price }}
            </p>
            <p><a href="{{ item.note.get_absolute_url }}">Описание товара</a></p>
        </div>
        <div class="add">
            <form action="{% url 'cart_add_note' item.note.pk %}" method="POST">
                {{ item.update_quantity_form.quantity }}
                {{ item.update_quantity_form.update }}
                {% csrf_token %}
                <hr>
                <input type="submit" value="Добавить в корзину" class="btn btn-primary btn-block">
                <a href="{% url 'cart_remove_note' item.note.pk %}" class="btn btn-primary btn-block">Удалить из
                    корзины</a>
            </form>
        </div>
        {%  endif %}
        {% if item.phone.pk %}
        <div class="item_name">
            <h3>Товар: {{ item.phone.brand }} {{ item.phone.name }}</h3>
        </div>
        <div class="item_body">
            <p>
                Идентификатор: {{ item.phone.pk }}
            </p>
            <p>
                Цена: {{ item.phone.price }}
            </p>
            <p>
                Количество: {{ item.quantity }} | Сумма: {{ item.total_price }}
            </p>
            <!-- phone - это модель товара Notebook, у нее вызываем метод get_absolute_url -->
            <p><a href="{{ item.phone.get_absolute_url }}">Описание товара</a></p>
        </div>
        <div class="add">
            <form action="{% url 'cart_add_phone' item.phone.pk %}" method="POST">
                {{ item.update_quantity_form.quantity }}
                {{ item.update_quantity_form.update }}
                {% csrf_token %}
                <hr>
                <input type="submit" value="Добавить в корзину" class="btn btn-primary btn-block">
                <a href="{% url 'cart_remove_phone' item.phone.pk %}" class="btn btn-primary btn-block">Удалить из
                    корзины</a>
            </form>
        </div>
        {% endif %}
    </div>
    {% endfor %}
</div>
{% else %}
<p>Корзина пуста</p>
{% endif %}
{% endif %}
{% endblock %}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey Tikhonov, 2020-02-18
@tumbler

The schema is wrong. A phone and a laptop are one and the same entity, a commodity.

V
Vladimir, 2020-02-19
@Realmixer

Let's say you put a laptop=5 in the cart, and then a phone=5. But there will be only one entry in the dictionary Cart.cart, because the keys are the same. This is a mistake once.
And now look at what you will have in the variables if you perform the substitution:

def __iter__(self):
        # перебор элементов корзины и получение их из базы данных
        product_ids = self.cart.keys() # [5]
        # получение объекта товара и добавление его в корзину
        notes = Notebook.objects.filter(id__in=product_ids) # Notebook.objects.filter(id__in=[5])
        phones = Phone.objects.filter(id__in=product_ids) # Phone.objects.filter(id__in=[5])

Naturally, phones and laptops with . This is error two. In fact, there are more errors here. But if you want to make this code work, then take a closer look at the logic of the . For example, you can change the keys to:id == 5
product_id = f'{product._meta.app_label}.{product._meta.object_name}.{product.pk}'

This will pull the changes in the entire class. But the cart will be able to contain any products with overlapping id's.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question