Корзина для интернет магазина на django
Привет всем. Такая таска: нужно сделать корзину для ИМ на джанго самую элементарную, чтобы при переходе в «Корзину», она выводила таблицу с именем товара, количеством и суммой, а также общей суммой товаров. Создал модели Product(продукт) и Cart(Корзина). Объясните пожалуйста механизм взаимодействия, кто за что цепляется и примеры, если можно. P.S. Сильно не пинайте пожалуйста, совсем новичок, делаю задание.
Отслеживать
задан 21 ноя 2013 в 19:24
9 4 4 серебряных знака 7 7 бронзовых знаков
github.com/UlugbekMuslitdinov/exizmat Могу привести в пример код моего интернет-магазина
15 янв 2021 в 15:52
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Отслеживать
ответ дан 21 ноя 2013 в 19:31
1,355 7 7 серебряных знаков 5 5 бронзовых знаков
Если это оно code.google.com/p/django-cart , то смотрел. Там нет кода моделей Cart и Product, поэтому я не очень понимаю. И с сессиями тоже не понимаю как, не знаю их. Если можете, объясните доходчиво, пожалуйста
21 ноя 2013 в 19:33
Есть и Cart, и generic relation на товар code.google.com/p/django-cart/source/browse/trunk/cart/… С сессиями все просто — Вы туда что-то кладете в одном запросе, и достаете в другом. Как это работает внутри — неважно сейчас.
Создание корзины
После создания каталога продуктов следующим шагом является создание корзины покупок, которая позволит пользователям выбирать продукты, которые они хотят приобрести. Корзина позволяет пользователям выбирать нужные продукты и временно хранить их во время просмотра сайта до тех пор, пока не будет размещен заказ. Корзина должна быть сохранена в сессии, чтобы элементы корзины хранились во время визита пользователя.
Мы будем использовать Django’s session framework для сохранения товаров корзины. Корзина будет храниться в сессии до тех пор, пока она не завершится. Нам также потребуется построить дополнительные модели Джанго для корзины и ее товаров.
results matching » «
No results matching » «
Хранение корзины покупок в сессиях
Необходимо создать простую структуру, которая может быть сериализована в JSON для хранения элементов корзины в сессии. Корзина должна включать следующие данные для каждого содержащегося в ней элемента:
- id экземпляра Product
- Количество товара, выбранное для данного продукта
- Цена единицы для данного продукта
Поскольку цены на продукцию могут различаться, мы приближаемся к сохранению цены продукта вместе с продуктом, когда он добавляется в корзину. Таким образом, мы будем сохранять ту же цену, которую пользователи увидели при добавлении товара в корзину, даже если цена продукта изменится после этого.
Теперь необходимо управлять созданием корзин и связывать их с сеансами. Корзина покупок должна работать следующим образом:
- Когда требуется корзина, мы проверяем, установлен ли пользовательский session key. Если в сессии не задана корзина, мы создадим новую корзину и сохраним ее в session key корзины.
- Для последовательных запросов мы выполняем одну и ту же проверку и получая номенклатуры корзины из session key корзины. Мы извлекаем элементы корзины из базы данных и связанные с ними объекты продукта.
Измените файл settings.py проекта и добавьте в него следующий параметр:
CART_SESSION_ID = 'cart'
Это ключ, который мы собираемся использовать для хранения корзины в сессии пользователя.
Давайте создадим приложение для управления корзинами покупок. Откройте терминал и создайте новое приложение, запустив следующую команду из каталога проекта:
python manage.py startapp cart
Затем отредактируйте файл settings.py проекта и добавьте «cart» к параметру INSTALLED_APPS следующим образом:
INSTALLED_APPS = ( # . 'shop', 'cart', )
Создайте новый файл в каталоге приложения cart и назовите его cart.py. Добавьте в него следующий код:
from decimal import Decimal from django.conf import settings from shop.models import Product class Cart(object): def __init__(self, request): """ Инициализируем корзину """ self.session = request.session cart = self.session.get(settings.CART_SESSION_ID) if not cart: # save an empty cart in the session cart = self.session[settings.CART_SESSION_ID] = <> self.cart = cart
Это класс Cart, который позволит нам управлять корзиной для покупок. Требуется инициализация корзины с помощью объекта request. Мы храним текущую сессию с помощью self.session = request.session, чтобы сделать его доступным для других методов класса Cart. Во-первых, мы пытаемся получить корзину с текущей сессии с помощью self.session.get(settings.CART_SESSION_ID). Если в сессии отсутствует корзина, то мы создадим сессию с пустой корзиной, установив пустой словарь в сессии. Мы ожидаем, что наш словарь корзины будет использовать коды продуктов в качестве ключей и словарь с количеством и ценой в качестве значения для каждого ключа. Таким образом, мы можем гарантировать, что продукт не будет добавлен в корзину более одного раза; можно также упростить доступ к данным элементов корзины.
Создадим метод для добавления продуктов в корзину или обновления их количества. Добавьте следующие методы add() и save() в класс Cart:
def add(self, product, quantity=1, update_quantity=False): """ Добавить продукт в корзину или обновить его количество. """ product_id = str(product.id) if product_id not in self.cart: 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
Метод add() принимает следующие параметры:
- product : Экземпляр Product для добавления или обновления в корзине
- quantity : Необязательное целое число для количества продукта. По умолчанию используется значение 1 .
- update_quantity : Это логическое значение, которое указывает, требуется ли обновление количества с заданным количеством (True), или же новое количество должно быть добавлено к существующему количеству (False).
id продукта используется в качестве ключа в словаре содержимого корзины. id продукта преобразуется в строку, так как Джанго использует JSON для сериализации данных сессии, а JSON разрешает только имена строк. id продукта — это ключ, а значение, которое мы сохраняем, — словарь с количеством и ценой для продукта. Цена продукта преобразуется из десятичного разделителя в строку, чтобы сериализовать его. Наконец, мы вызываем метод save(), чтобы сохранить корзину в сессии.
Метод save() сохраняет все изменения в корзине в сессии и помечает сессию как modified с помощью session.modified = True. Это говорит о том, что сессия modified и должна быть сохранена.
Нам также нужен метод для удаления продуктов из корзины. Добавьте следующий метод в класс Cart:
def remove(self, product): """ Удаление товара из корзины. """ product_id = str(product.id) if product_id in self.cart: del self.cart[product_id] self.save()
Метод remove() удаляет заданный продукт из словаря корзины и вызывает метод save() для обновления корзины в сессии.
Нам придется перебрать элементы, содержащихся в корзине, и получить доступ к соответствующим экземплярам Product. Для этого в классе можно определить метод __iter__(). Добавьте следующий метод в класс Cart:
def __iter__(self): """ Перебор элементов в корзине и получение продуктов из базы данных. """ product_ids = self.cart.keys() # получение объектов product и добавление их в корзину products = Product.objects.filter(id__in=product_ids) for product in products: self.cart[str(product.id)]['product'] = product for item in self.cart.values(): item['price'] = Decimal(item['price']) item['total_price'] = item['price'] * item['quantity'] yield item
В методе __iter__() мы извлекаем экземпляры продукта, присутствующие в корзине, чтобы включить их в номенклатуры корзины. Наконец, мы проходим по элементам корзины, преобразуя цену номенклатуры обратно в десятичное число и добавляя атрибут total_price к каждому элементу. Теперь можно легко выполнить итерацию по товарам в корзине.
Нам также нужен способ вернуть общее количество товаров в корзине. Когда функция len() выполняется на объекте, Python вызывает метод __len__() для извлечения ее длины. Мы собираемся определить пользовательский метод __len__(), чтобы вернуть общее количество элементов, хранящихся в корзине. Добавьте следующий метод __len__() в класс Cart:
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 готов к управлению корзиной для покупок.
Как реализовать корзину на django?
Только начал изучать django, строго не судите. Есть модель книги и модель корзины куда надо эту книгу и закинуть.
Для корзины создал отдельное приложение. На странице подробного описания книги создал ссылки для добавления ее в корзину.
a href="" Добавить книгу в корзину
По ссылке переходит, все работает, но объект книги в корзину не добавляет.
Что здесь не так?
class Book(models.Model): title = models.CharField(max_length=200) author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True) summary = models.TextField( max_length=1000, null=True, blank=True, help_text="Enter a brief description of the book" ) isbn = models.CharField( max_length=13, blank=True, help_text='13 Character ISBN number') genre = models.ManyToManyField( Genre, help_text="Select a genre for this book", blank=True) def display_genre(self): return ','.join(genre.name for genre in self.genre.all()[:3]) display_genre.short_description = 'Genre' def __str__(self): return self.title def get_absolute_url(self): return reverse("book_detail", args=[str(self.id)])
class Basket(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='basket') book = models.ForeignKey( Book, on_delete=models.CASCADE) quantity = models.PositiveIntegerField( verbose_name='количество', default=0) add_datetime = models.DateTimeField( verbose_name='время', auto_now_add=True)
def basket(request): content = <> return render(request, 'basketapp/basket.html', content) def basket_add(request, pk): book = get_object_or_404(Book, pk=pk) basket = Basket.objects.filter(user=request.user, book=book).first() if not basket: basket = Basket(user=request.user, book=book) basket.quantity += 1 basket.save() return HttpResponseRedirect(reverse('basketapp:basket')) def basket_remove(request, pk): content = <> return render(request, 'basketapp/basket.html', content)
- Вопрос задан более трёх лет назад
- 9106 просмотров
1 комментарий
Простой 1 комментарий
Модератор @TosterModerator
3. В процессе создания вопроса пользователь Сервиса обязан:
3.8. Использовать для демонстрации фрагментов кода только специальный тег
Решения вопроса 0
Ответы на вопрос 2
1. Оформи код соответственно
2. Модель херня. Научись О2М связям
3. Стоит ли хранить корзины на бэкенде? Их хранят на бэкенде, когда любят спамить людей, бросивших корзины
4. В коде
basket = Basket.objects.filter(user=request.user, book=book).first() if not basket: basket = Basket(user=request.user, book=book) basket.quantity += 1 basket.save()
Вот пример одной корзины, которую я делал несколько лет назад.
basket.py
from collections import UserDict from core.models import ProductOption, Product from .models import Item class Basket(UserDict): changed = False def add(self, quantity=0, option=None, set_=False): self.changed = True id_ = str(option.product.id) option = str(option.id) self.setdefault(id_, <>) self[id_].setdefault(option, 0) if set_: self[id_][option] = quantity else: self[id_][option] += quantity if self[id_][option] return sum(x * prices[product] for product, options in self.items() for _, x in options.items()) def cost(self, option): price = option.product.price return self.count_option(option) * price def count_option(self, option): product_id = str(option.product.id) option_id = str(option.id) return self.get(product_id, <>).get(option_id, 0) def flush(self): self.changed = True for key in list(self): del self[key] def build_order(self, order): items = [] for product_id, data in self.items(): product = Product.objects.get(id=product_id) for option_id, quantity in data.items(): if quantity == 0: continue option = None if option_id != '0': option = ProductOption.objects.get(id=option_id) items.append( Item(order=order, option=option, quantity=quantity, product=product) ) order.items.bulk_create(items) self.flush() return order def fix(self): """Фиксит корзину на случай, если опции удалили, а они находятся в корзине""" ids = self.keys() exist_in_db = (Product.objects .filter(id__in=ids, options__in_stock=True, options__show=True) .values_list('id', flat=True)) to_remove = set(ids) - set(str(x) for x in exist_in_db) for id_ in to_remove: del self[id_] if to_remove: self.changed = True def to_dict(self): return dict(self)
middleware.py
from django.utils.deprecation import MiddlewareMixin from .basket import Basket class BasketMiddleware(MiddlewareMixin): def process_request(self, request): request.basket = Basket(request.session.get('basket', <>)) def process_response(self, request, response): if getattr(request, 'basket', None) is None: return response if request.basket.changed: request.session['basket'] = request.basket.to_dict() request.session.save() return response
settings.py
# . SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' MIDDLEWARE_CLASSES = [ # . 'orders.middleware.BasketMiddleware', ] # .
views.py
@method_decorator(csrf_exempt, name='dispatch') class ChangeBasketOption(View): def post(self, request): change = int(request.POST.get('change')) pk = int(request.POST.get('id')) set_ = bool(request.POST.get('set', 0)) option = get_object_or_404(ProductOption, pk=pk) value = request.basket.add(option=option, quantity=change, set_=set_) cost = request.basket.cost(option) return JsonResponse(< 'value': value, 'cost': cost, 'total': request.basket.total_price >) class Basket(FormView): template_name = 'orders/basket.html' form_class = OrderForm success_url = reverse_lazy('ordered') def get(self, request, *args, **kwargs): request.basket.fix() return super().get(request, *args, **kwargs) def get_context_data(self, **kwargs): kwargs['products'] = Product.objects.filter(id__in=self.request.basket.keys()) kwargs['can_order'] = self.request.basket.total_price >= min_order_cost() return super().get_context_data(**kwargs) def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs['user'] = self.request.user return kwargs def form_valid(self, form): order = form.save() order = self.request.basket.build_order(order) mail_new_order(order) return super().form_valid(form)
Смысл в том, что все корзины хранятся только в куках (из-за SESSION_ENGINE) у самих пользователей. Это означает, что хоть миллиард юзеров зайдёт и добавят по миллиону товаров — они не прибавят ни байта занимаемого места на HDD, пока не сделают заказ. К тому же, куки — очень быстрое хранилище и изменения в корзине происходят моментально. К примеру, AJAX запросы в ChangeBasketOption в среднем занимают 30мс в браузере.