• Как перенаправить на странницу пользователя из комментариев?

    @kyern
    Быдлокодер без стажа
    В качестве id надо передавать не comm.user.pk, а comm.name.pk
    Но вообще я бы порекомендовал использовать для поля имя user, а не name, как видите, такое название уже ввело вас в заблуждение.
    Ответ написан
    Комментировать
  • Как реализовать корзину на django?

    @deliro
    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] <= 0:
                del self[id_][option]
                if not self[id_]:
                    del self[id_]
                return 0
            else:
                return self[id_][option]
    
        @property
        def total_count(self):
            return sum(x for product, options in self.items() for _, x in options.items())
    
        @property
        def total_price(self):
            prices = {str(id_): price for id_, price in
                      Product.objects.filter(id__in=self.keys()).values_list('id', 'price')}
            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мс в браузере.
    Ответ написан
    Комментировать