• Насколько законно парсить каталог товаров магазина?

    fox_12
    @fox_12
    Расставляю биты, управляю заряженными частицами
    Каталог товаров является публичной офертой неопределенному кругу лиц. Соответственно - вы можете с ней ознакомиться в том числе парсингом каталога.
    Единственно нужно знать меру - если вы массой своих запросов валите сервер, - вы затрудняете доступ других к ее ознакомлению, и можете нанести прямой ущерб владельцу. Скажем другие не могут зайти в каталог или оплатить товар, пока ваш классный многопоточный скрипт грузит сервер...
    А эти деяния могут подпадать вплоть до норм уголовного кодекса.
    Ответ написан
    Комментировать
  • Как сделать ссылку без параметров?

    @grek_cheburek
    Программист самоучка
    Знать бы еще, что для вас является красивым адресом. Если вам нужно подставить номер аккаунта, то можно же сделать так.
    domain.com/id1234
    Если вы хотите не номер, а логин, тогда примерно так.
    domain.com/greck_chebureck

    Логика такого запроса одновременно и легка и тяжела.
    Во-первых, вам нужно использовать модуль чпу. Его можно подключить в файле .htaccess. Во-вторых вам нужно определиться, какие глобальные переменные из массива $_GET являются главными в вашем проекте.
    У меня, к примеру, глобальная переменная из массива $_GET['lang'] является главной и в обязательном порядке посылается к каждой страницы проекта.
    Далее вам нужно решить, где у вас находится папка с аккаунтам пользователя.
    К ней, в файле htaccess прописывайте путь, примерно так.
    RewriteRule ^([a-z0-9-_.]+)$ /user-page/index.php?login=$1
    RewriteRule ^([0-9]+)$ /user-page/index.php?id=$1
    Ну а в php отлавливать, какая переменная пришла на страницу. id или login.
    Если login, Тогда пользователя вызываем по логину, если id, тогда по номеру аккаунта.

    И помните, все аккаунты нужно хранить в базе данных. А то я понял, что для каждого пользователя вы хотите создать отдельный файл php.
    Этого делать не нужно.
    Ответ написан
    Комментировать
  • Возникает ошибка Server Error 500 при попытке добавления статьи из админки, как-то связана с переходом на http2, логи не помогают, куда копать?

    DmitryVoronkov
    @DmitryVoronkov
    Python Developer
    Настрой один раз логирование на продакшене и лови ошибки на почту.
    Хоть кто-нибудь читает документацию?
    ADMINS = (('Your nam.', 'mailfor_error@gmail.com'),)
    ...
    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_HOST = 'smtp.yandex.ru' # or google
    EMAIL_HOST_PASSWORD = 'password'
    EMAIL_HOST_USER = 'login'
    DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
    SERVER_EMAIL = DEFAULT_FROM_EMAIL
    EMAIL_PORT = 465
    EMAIL_USE_SSL = True
    ...
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': True,
        'formatters': {
            'verbose': {
                'format': '%(levelname)s %(asctime)s %(module)s '
                          '%(process)d %(thread)d %(message)s'
            },
            'simple': {
                'format': '%(levelname)s %(message)s'
            },
        },
        'handlers': {
            'null': {
                'level': 'DEBUG',
                'class': 'django.utils.log.NullHandler',
            },
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            'mail_admins': {
                'level': 'ERROR',
                'class': 'django.utils.log.AdminEmailHandler',
                'include_html': True,
            }
        },
        'loggers': {
            'django': {
                'handlers': ['console'],
                'propagate': True,
                'level': 'INFO',
            },
            'django.db': {
                'level': 'DEBUG',
                'handlers': ['console'],
                'propagate': True,
            },
            'django.request': {
                'handlers': ['mail_admins', 'console'],
                'level': 'ERROR',
                'propagate': False,
            },
        }
    }
    Ответ написан
    2 комментария
  • Как в PyCharm из проекта создать репозиторий на GitHub?

    @balamut108
    Py
    Создаёте новый проект, активируете VCS (Enable VCS), создаёте новый репозиторий Git, добавляете в него нужные файлы, делаете коммит, далее в VCS выбираете Import Into Version Control -> Share Project in GitHub.
    Это будет работать при условии что у Вас корректно настроены VCS в Settings -> Version Control.
    Ответ написан
    1 комментарий
  • Байт вмещает 256 символов?

    AxisPod
    @AxisPod
    Увы байт не имеет за собой квантовой основы и сохранить в одном байте 256 чисел одновременно вы не сможете.
    Ответ написан
    Комментировать
  • Как реализовать корзину на 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мс в браузере.
    Ответ написан
    Комментировать