Храните дополнительную информацию о продукте перед добавлением в корзину

Tl ;dr Как мне поменять add-product-to-cart-footer добавить экземпляр другой модели, который является комбинацией этого продукта и другой информации?

Я продаю очки, поэтому, несмотря на то, что у нас есть страница сведений о продукте, показывающая информацию о раме и варианте оправы (в зависимости от цвета и размера), клиент также должен заполнить форму для определения типа линз, которые он хочет получить с этой оправой.,

Одним из вариантов может быть сохранение каждой перестановки варианта кадра и комбинации объективов в виде варианта кадра в базе данных, как различные варианты хранения для смартфонов, но я не думаю, что это было бы хорошей идеей, потому что:

  • Есть десятки возможных вариантов объектива
  • доступные объективы практически не зависят от выбранной оправы
  • было бы трудно хранить информацию о запасе вариантов кадра, если бы у нас были только варианты кадра + линзы. (Я использую Django Shop 1.1, который добавляет управляющий запас.)

Вместо этого я думаю о модели Glasses с внешними ключами для варианта оправы и линз, и это то, что будет добавлено в корзину.

class Lenses(models.Model):
    material = models.CharField(choices=...)
    anti_reflective = models.CharField(choices=...)
    # ...

class Glasses(models.Model):
    frame = models.ForeignKey(FrameVariant)
    lenses = models.ForeignKey(Lenses)

Я бы хотел изменить кнопку "Добавить в корзину", чтобы вместо добавления варианта рамки в корзину он переходил в форму (возможно, наложенную на той же странице), чтобы выбрать линзы. Соответствующий блок для переопределения add-product-to-cart-footer из shop/catalog/product-add2cart:

{% block add-product-to-cart-footer %}
  <div class="card-footer bg-white">
    <div class="d-flex flex-column flex-lg-row justify-content-between">
      <button class="btn btn-secondary m-1" ng-disabled="context.is_in_cart" ng-click="do(addToCart('{% url "shop:watch-list" %}'))">
        {% trans "Watch product" %}
        <i class="fa" ng-class="context.is_in_cart ? 'fa-heart' : 'fa-heart-o'"></i>
      </button>
      {% url "shop:cart-list" as cart_endpoint %}{% trans "The product has been successfully placed in the shopping cart:" as modal_title %}
      <button
        class="btn btn-primary m-1"
        ng-disabled="!context.availability.quantity"
        ng-click="
          {% if use_modal_dialog %}
            do(openModal('{{ modal_title }}'))
              .then(addToCart('{{ cart_endpoint }}'))
              .then(redirectTo())
          {% else %}
            do(addToCart('{{ cart_endpoint }}'))
              .then(emit('shop.cart.change'))
          {% endif %}
        "
      >
        {% trans "Add to cart" %}
        <i class="fa fa-cart-arrow-down"></i>
      </button>
    </div>
    {% if request.session.is_empty %}
      <small class="text-muted m-1">{% block cookie-disclaimer %}
        {% blocktrans %}By adding a product to the cart you are giving consent to cookies being used.{% endblocktrans %}
      {% endblock %}</small>
    {% endif %}
  </div>
{% endblock add-product-to-cart-footer %}

addToCart(endpoint) из магазина /static/shop/js/catalog.js:

scope.addToCart = function(endpoint) {
 return function(context) {
  var deferred = $q.defer();
  $http.post(endpoint, scope.context).then(function(response) {
   scope.context.is_in_cart = true;
   deferred.resolve(context);
  }).catch(function(response) {
   $log.error('Unable to update context: ' + response.statusText);
   deferred.reject();
  });
  return deferred.promise;
 };
};

Это выглядит как context это то, что определяет, что добавляется в корзину, и вот что я должен изменить. Кажется, что context может быть передан мимо shop/cascade/catalog.py:

class ShopAddToCartPlugin(ShopPluginBase):
    name = _("Add Product to Cart")
    require_parent = True
    parent_classes = ('BootstrapColumnPlugin',)
    cache = False

    use_modal_dialog = GlossaryField(
        widgets.CheckboxInput(),
        label=_("Use Modal Dialog"),
        initial='on',
        help_text=_("After adding product to cart, render a modal dialog"),
    )

    def get_render_template(self, context, instance, placeholder):
        templates = []
        if instance.glossary.get('render_template'):
            templates.append(instance.glossary['render_template'])
        if context['product'].managed_availability():
            template_prefix = 'available-'
        else:
            template_prefix = ''
        templates.extend([
            '{}/catalog/{}product-add2cart.html'.format(app_settings.APP_LABEL, template_prefix),
            'shop/catalog/{}product-add2cart.html'.format(template_prefix),
        ])
        return select_template(templates)

    def render(self, context, instance, placeholder):
        context = super(ShopAddToCartPlugin, self).render(context, instance, placeholder)
        context['use_modal_dialog'] = bool(instance.glossary.get('use_modal_dialog', True))
        return context

Поиск ShopAddToCartPlugin не обнаружил каких-либо заметных применений ни в коде Django Shop, ни в том, что было создано Cookiecutter, поэтому я не уверен, какой context будет передан render,

РЕДАКТИРОВАТЬ: Другой вариант - добавить вариант рамки в корзину, как обычно, но перенаправить на форму линзы, которая создает объект "Линзы", связанный с этим вариантом рамки. Кажется, это может быть проще.

Чтобы помочь с визуализацией шаблона, вот как выглядит Django Shop:

1 ответ

В аналогичном случае я держал продукты в корзине как отдельные предметы. Это означает, что я не буду использовать внешний ключ от Glasses в Lenses,

Вместо этого я бы создал специальный AddGlassCartSerializer(...), который проверяет предоставленные (размещенные) данные. Там я бы различал рамку, левый и правый объектив. Возможно, вам даже придется отслеживать ориентацию линз, если вы предлагаете анизотропные варианты.

Затем, добавив стакан в корзину, вы всегда получаете 3 предмета: оправу, левый и правый объектив.

Другие вопросы по тегам