We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Variants displayed in product add to cart form even when product type has no variants
### What I'm trying to achieve

...Smaller form for products with no variants

### Steps to reproduce the problem

1. Create a product type with no variants
2. Create a product based on that product type
3. Open product details page in the consumer website

### What I expected to happen

...Variants field is not shown when product has no variants

### What happened instead/how it failed

...Variants field is displayed with SKU and price

(Please include a stack trace if this problem results in a crash.)
![capture](https://user-images.githubusercontent.com/6353787/34457534-47bc27fc-edab-11e7-9197-5ffff5d033cd.JPG)

Mostly I'm wondering if this is expected behaviour? Displaying a product form containing only one option showing the SKU seems a bit odd for the enduser. In my app, I am probably going to set the product variant field to hidden in the product variant form for products with no variants.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `saleor/product/views.py`
Content:
```
1 import datetime
2 import json
3 
4 from django.conf import settings
5 from django.http import HttpResponsePermanentRedirect, JsonResponse
6 from django.shortcuts import get_object_or_404, redirect
7 from django.template.response import TemplateResponse
8 from django.urls import reverse
9 
10 from ..cart.utils import set_cart_cookie
11 from ..core.utils import get_paginator_items, serialize_decimal
12 from ..core.utils.filters import get_now_sorted_by, get_sort_by_choices
13 from .filters import ProductFilter, SORT_BY_FIELDS
14 from .models import Category
15 from .utils import (
16     get_availability, get_product_attributes_data, get_product_images,
17     get_variant_picker_data, handle_cart_form, product_json_ld,
18     products_for_cart, products_with_availability, products_with_details)
19 
20 
21 def product_details(request, slug, product_id, form=None):
22     """Product details page
23 
24     The following variables are available to the template:
25 
26     product:
27         The Product instance itself.
28 
29     is_visible:
30         Whether the product is visible to regular users (for cases when an
31         admin is previewing a product before publishing).
32 
33     form:
34         The add-to-cart form.
35 
36     price_range:
37         The PriceRange for the product including all discounts.
38 
39     undiscounted_price_range:
40         The PriceRange excluding all discounts.
41 
42     discount:
43         Either a Price instance equal to the discount value or None if no
44         discount was available.
45 
46     local_price_range:
47         The same PriceRange from price_range represented in user's local
48         currency. The value will be None if exchange rate is not available or
49         the local currency is the same as site's default currency.
50     """
51     products = products_with_details(user=request.user)
52     product = get_object_or_404(products, id=product_id)
53     if product.get_slug() != slug:
54         return HttpResponsePermanentRedirect(product.get_absolute_url())
55     today = datetime.date.today()
56     is_visible = (
57         product.available_on is None or product.available_on <= today)
58     if form is None:
59         form = handle_cart_form(request, product, create_cart=False)[0]
60     availability = get_availability(product, discounts=request.discounts,
61                                     local_currency=request.currency)
62     product_images = get_product_images(product)
63     variant_picker_data = get_variant_picker_data(
64         product, request.discounts, request.currency)
65     product_attributes = get_product_attributes_data(product)
66     show_variant_picker = all([v.attributes for v in product.variants.all()])
67     json_ld_data = product_json_ld(product, availability, product_attributes)
68     return TemplateResponse(
69         request, 'product/details.html',
70         {'is_visible': is_visible,
71          'form': form,
72          'availability': availability,
73          'product': product,
74          'product_attributes': product_attributes,
75          'product_images': product_images,
76          'show_variant_picker': show_variant_picker,
77          'variant_picker_data': json.dumps(
78              variant_picker_data, default=serialize_decimal),
79          'json_ld_product_data': json.dumps(
80              json_ld_data, default=serialize_decimal)})
81 
82 
83 def product_add_to_cart(request, slug, product_id):
84     # types: (int, str, dict) -> None
85 
86     if not request.method == 'POST':
87         return redirect(reverse(
88             'product:details',
89             kwargs={'product_id': product_id, 'slug': slug}))
90 
91     products = products_for_cart(user=request.user)
92     product = get_object_or_404(products, pk=product_id)
93     form, cart = handle_cart_form(request, product, create_cart=True)
94     if form.is_valid():
95         form.save()
96         if request.is_ajax():
97             response = JsonResponse({'next': reverse('cart:index')}, status=200)
98         else:
99             response = redirect('cart:index')
100     else:
101         if request.is_ajax():
102             response = JsonResponse({'error': form.errors}, status=400)
103         else:
104             response = product_details(request, slug, product_id, form)
105     if not request.user.is_authenticated:
106         set_cart_cookie(cart, response)
107     return response
108 
109 
110 def category_index(request, path, category_id):
111     category = get_object_or_404(Category, id=category_id)
112     actual_path = category.get_full_path()
113     if actual_path != path:
114         return redirect('product:category', permanent=True, path=actual_path,
115                         category_id=category_id)
116     products = (products_with_details(user=request.user)
117                 .filter(categories__id=category.id)
118                 .order_by('name'))
119     product_filter = ProductFilter(
120         request.GET, queryset=products, category=category)
121     products_paginated = get_paginator_items(
122         product_filter.qs, settings.PAGINATE_BY, request.GET.get('page'))
123     products_and_availability = list(products_with_availability(
124         products_paginated, request.discounts, request.currency))
125     now_sorted_by = get_now_sorted_by(product_filter)
126     arg_sort_by = request.GET.get('sort_by')
127     is_descending = arg_sort_by.startswith('-') if arg_sort_by else False
128     ctx = {'category': category, 'filter_set': product_filter,
129            'products': products_and_availability,
130            'products_paginated': products_paginated,
131            'sort_by_choices': get_sort_by_choices(product_filter),
132            'now_sorted_by': now_sorted_by,
133            'is_descending': is_descending}
134     return TemplateResponse(request, 'category/index.html', ctx)
135
```

Path: `saleor/product/forms.py`
Content:
```
1 import json
2 
3 from django import forms
4 from django.utils.encoding import smart_text
5 from django.utils.translation import pgettext_lazy
6 from django_prices.templatetags.prices_i18n import gross
7 
8 from ..cart.forms import AddToCartForm
9 
10 
11 class VariantChoiceField(forms.ModelChoiceField):
12     discounts = None
13 
14     def label_from_instance(self, obj):
15         variant_label = smart_text(obj)
16         label = pgettext_lazy(
17             'Variant choice field label',
18             '%(variant_label)s - %(price)s') % {
19                 'variant_label': variant_label,
20                 'price': gross(obj.get_price(discounts=self.discounts))}
21         return label
22 
23 
24 class ProductForm(AddToCartForm):
25     variant = VariantChoiceField(queryset=None)
26 
27     def __init__(self, *args, **kwargs):
28         super().__init__(*args, **kwargs)
29         variant_field = self.fields['variant']
30         variant_field.queryset = self.product.variants
31         variant_field.discounts = self.cart.discounts
32         variant_field.empty_label = None
33         images_map = {variant.pk: [vi.image.image.url
34                                    for vi in variant.variant_images.all()]
35                       for variant in self.product.variants.all()}
36         variant_field.widget.attrs['data-images'] = json.dumps(images_map)
37 
38     def get_variant(self, cleaned_data):
39         return cleaned_data.get('variant')
40 
41
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/saleor/product/forms.py b/saleor/product/forms.py
--- a/saleor/product/forms.py
+++ b/saleor/product/forms.py
@@ -11,6 +11,9 @@
 class VariantChoiceField(forms.ModelChoiceField):
     discounts = None
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
     def label_from_instance(self, obj):
         variant_label = smart_text(obj)
         label = pgettext_lazy(
@@ -20,6 +23,20 @@
                 'price': gross(obj.get_price(discounts=self.discounts))}
         return label
 
+    def update_field_data(self, variants, cart):
+        """ Function initializing fields custom data """
+        self.queryset = variants
+        self.discounts = cart.discounts
+        self.empty_label = None
+        images_map = {variant.pk: [vi.image.image.url
+                                   for vi in variant.variant_images.all()]
+                      for variant in variants.all()}
+        self.widget.attrs['data-images'] = json.dumps(images_map)
+        # Don't display select input if there are less than two variants
+        if self.queryset.count() < 2:
+            self.widget = forms.HiddenInput(
+                {'value': variants.all()[0].pk})
+
 
 class ProductForm(AddToCartForm):
     variant = VariantChoiceField(queryset=None)
@@ -27,14 +44,7 @@
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         variant_field = self.fields['variant']
-        variant_field.queryset = self.product.variants
-        variant_field.discounts = self.cart.discounts
-        variant_field.empty_label = None
-        images_map = {variant.pk: [vi.image.image.url
-                                   for vi in variant.variant_images.all()]
-                      for variant in self.product.variants.all()}
-        variant_field.widget.attrs['data-images'] = json.dumps(images_map)
+        variant_field.update_field_data(self.product.variants, self.cart)
 
     def get_variant(self, cleaned_data):
         return cleaned_data.get('variant')
-
diff --git a/saleor/product/views.py b/saleor/product/views.py
--- a/saleor/product/views.py
+++ b/saleor/product/views.py
@@ -63,6 +63,7 @@
     variant_picker_data = get_variant_picker_data(
         product, request.discounts, request.currency)
     product_attributes = get_product_attributes_data(product)
+    # show_variant_picker determines if variant picker is used or select input
     show_variant_picker = all([v.attributes for v in product.variants.all()])
     json_ld_data = product_json_ld(product, availability, product_attributes)
     return TemplateResponse(

{"golden_diff": "diff --git a/saleor/product/forms.py b/saleor/product/forms.py\n--- a/saleor/product/forms.py\n+++ b/saleor/product/forms.py\n@@ -11,6 +11,9 @@\n class VariantChoiceField(forms.ModelChoiceField):\n     discounts = None\n \n+    def __init__(self, *args, **kwargs):\n+        super().__init__(*args, **kwargs)\n+\n     def label_from_instance(self, obj):\n         variant_label = smart_text(obj)\n         label = pgettext_lazy(\n@@ -20,6 +23,20 @@\n                 'price': gross(obj.get_price(discounts=self.discounts))}\n         return label\n \n+    def update_field_data(self, variants, cart):\n+        \"\"\" Function initializing fields custom data \"\"\"\n+        self.queryset = variants\n+        self.discounts = cart.discounts\n+        self.empty_label = None\n+        images_map = {variant.pk: [vi.image.image.url\n+                                   for vi in variant.variant_images.all()]\n+                      for variant in variants.all()}\n+        self.widget.attrs['data-images'] = json.dumps(images_map)\n+        # Don't display select input if there are less than two variants\n+        if self.queryset.count() < 2:\n+            self.widget = forms.HiddenInput(\n+                {'value': variants.all()[0].pk})\n+\n \n class ProductForm(AddToCartForm):\n     variant = VariantChoiceField(queryset=None)\n@@ -27,14 +44,7 @@\n     def __init__(self, *args, **kwargs):\n         super().__init__(*args, **kwargs)\n         variant_field = self.fields['variant']\n-        variant_field.queryset = self.product.variants\n-        variant_field.discounts = self.cart.discounts\n-        variant_field.empty_label = None\n-        images_map = {variant.pk: [vi.image.image.url\n-                                   for vi in variant.variant_images.all()]\n-                      for variant in self.product.variants.all()}\n-        variant_field.widget.attrs['data-images'] = json.dumps(images_map)\n+        variant_field.update_field_data(self.product.variants, self.cart)\n \n     def get_variant(self, cleaned_data):\n         return cleaned_data.get('variant')\n-\ndiff --git a/saleor/product/views.py b/saleor/product/views.py\n--- a/saleor/product/views.py\n+++ b/saleor/product/views.py\n@@ -63,6 +63,7 @@\n     variant_picker_data = get_variant_picker_data(\n         product, request.discounts, request.currency)\n     product_attributes = get_product_attributes_data(product)\n+    # show_variant_picker determines if variant picker is used or select input\n     show_variant_picker = all([v.attributes for v in product.variants.all()])\n     json_ld_data = product_json_ld(product, availability, product_attributes)\n     return TemplateResponse(\n", "issue": "Variants displayed in product add to cart form even when product type has no variants\n### What I'm trying to achieve\r\n\r\n...Smaller form for products with no variants\r\n\r\n### Steps to reproduce the problem\r\n\r\n1. Create a product type with no variants\r\n2. Create a product based on that product type\r\n3. Open product details page in the consumer website\r\n\r\n### What I expected to happen\r\n\r\n...Variants field is not shown when product has no variants\r\n\r\n### What happened instead/how it failed\r\n\r\n...Variants field is displayed with SKU and price\r\n\r\n(Please include a stack trace if this problem results in a crash.)\r\n![capture](https://user-images.githubusercontent.com/6353787/34457534-47bc27fc-edab-11e7-9197-5ffff5d033cd.JPG)\r\n\r\nMostly I'm wondering if this is expected behaviour? Displaying a product form containing only one option showing the SKU seems a bit odd for the enduser. In my app, I am probably going to set the product variant field to hidden in the product variant form for products with no variants.\n", "before_files": [{"content": "import datetime\nimport json\n\nfrom django.conf import settings\nfrom django.http import HttpResponsePermanentRedirect, JsonResponse\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.urls import reverse\n\nfrom ..cart.utils import set_cart_cookie\nfrom ..core.utils import get_paginator_items, serialize_decimal\nfrom ..core.utils.filters import get_now_sorted_by, get_sort_by_choices\nfrom .filters import ProductFilter, SORT_BY_FIELDS\nfrom .models import Category\nfrom .utils import (\n    get_availability, get_product_attributes_data, get_product_images,\n    get_variant_picker_data, handle_cart_form, product_json_ld,\n    products_for_cart, products_with_availability, products_with_details)\n\n\ndef product_details(request, slug, product_id, form=None):\n    \"\"\"Product details page\n\n    The following variables are available to the template:\n\n    product:\n        The Product instance itself.\n\n    is_visible:\n        Whether the product is visible to regular users (for cases when an\n        admin is previewing a product before publishing).\n\n    form:\n        The add-to-cart form.\n\n    price_range:\n        The PriceRange for the product including all discounts.\n\n    undiscounted_price_range:\n        The PriceRange excluding all discounts.\n\n    discount:\n        Either a Price instance equal to the discount value or None if no\n        discount was available.\n\n    local_price_range:\n        The same PriceRange from price_range represented in user's local\n        currency. The value will be None if exchange rate is not available or\n        the local currency is the same as site's default currency.\n    \"\"\"\n    products = products_with_details(user=request.user)\n    product = get_object_or_404(products, id=product_id)\n    if product.get_slug() != slug:\n        return HttpResponsePermanentRedirect(product.get_absolute_url())\n    today = datetime.date.today()\n    is_visible = (\n        product.available_on is None or product.available_on <= today)\n    if form is None:\n        form = handle_cart_form(request, product, create_cart=False)[0]\n    availability = get_availability(product, discounts=request.discounts,\n                                    local_currency=request.currency)\n    product_images = get_product_images(product)\n    variant_picker_data = get_variant_picker_data(\n        product, request.discounts, request.currency)\n    product_attributes = get_product_attributes_data(product)\n    show_variant_picker = all([v.attributes for v in product.variants.all()])\n    json_ld_data = product_json_ld(product, availability, product_attributes)\n    return TemplateResponse(\n        request, 'product/details.html',\n        {'is_visible': is_visible,\n         'form': form,\n         'availability': availability,\n         'product': product,\n         'product_attributes': product_attributes,\n         'product_images': product_images,\n         'show_variant_picker': show_variant_picker,\n         'variant_picker_data': json.dumps(\n             variant_picker_data, default=serialize_decimal),\n         'json_ld_product_data': json.dumps(\n             json_ld_data, default=serialize_decimal)})\n\n\ndef product_add_to_cart(request, slug, product_id):\n    # types: (int, str, dict) -> None\n\n    if not request.method == 'POST':\n        return redirect(reverse(\n            'product:details',\n            kwargs={'product_id': product_id, 'slug': slug}))\n\n    products = products_for_cart(user=request.user)\n    product = get_object_or_404(products, pk=product_id)\n    form, cart = handle_cart_form(request, product, create_cart=True)\n    if form.is_valid():\n        form.save()\n        if request.is_ajax():\n            response = JsonResponse({'next': reverse('cart:index')}, status=200)\n        else:\n            response = redirect('cart:index')\n    else:\n        if request.is_ajax():\n            response = JsonResponse({'error': form.errors}, status=400)\n        else:\n            response = product_details(request, slug, product_id, form)\n    if not request.user.is_authenticated:\n        set_cart_cookie(cart, response)\n    return response\n\n\ndef category_index(request, path, category_id):\n    category = get_object_or_404(Category, id=category_id)\n    actual_path = category.get_full_path()\n    if actual_path != path:\n        return redirect('product:category', permanent=True, path=actual_path,\n                        category_id=category_id)\n    products = (products_with_details(user=request.user)\n                .filter(categories__id=category.id)\n                .order_by('name'))\n    product_filter = ProductFilter(\n        request.GET, queryset=products, category=category)\n    products_paginated = get_paginator_items(\n        product_filter.qs, settings.PAGINATE_BY, request.GET.get('page'))\n    products_and_availability = list(products_with_availability(\n        products_paginated, request.discounts, request.currency))\n    now_sorted_by = get_now_sorted_by(product_filter)\n    arg_sort_by = request.GET.get('sort_by')\n    is_descending = arg_sort_by.startswith('-') if arg_sort_by else False\n    ctx = {'category': category, 'filter_set': product_filter,\n           'products': products_and_availability,\n           'products_paginated': products_paginated,\n           'sort_by_choices': get_sort_by_choices(product_filter),\n           'now_sorted_by': now_sorted_by,\n           'is_descending': is_descending}\n    return TemplateResponse(request, 'category/index.html', ctx)\n", "path": "saleor/product/views.py"}, {"content": "import json\n\nfrom django import forms\nfrom django.utils.encoding import smart_text\nfrom django.utils.translation import pgettext_lazy\nfrom django_prices.templatetags.prices_i18n import gross\n\nfrom ..cart.forms import AddToCartForm\n\n\nclass VariantChoiceField(forms.ModelChoiceField):\n    discounts = None\n\n    def label_from_instance(self, obj):\n        variant_label = smart_text(obj)\n        label = pgettext_lazy(\n            'Variant choice field label',\n            '%(variant_label)s - %(price)s') % {\n                'variant_label': variant_label,\n                'price': gross(obj.get_price(discounts=self.discounts))}\n        return label\n\n\nclass ProductForm(AddToCartForm):\n    variant = VariantChoiceField(queryset=None)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        variant_field = self.fields['variant']\n        variant_field.queryset = self.product.variants\n        variant_field.discounts = self.cart.discounts\n        variant_field.empty_label = None\n        images_map = {variant.pk: [vi.image.image.url\n                                   for vi in variant.variant_images.all()]\n                      for variant in self.product.variants.all()}\n        variant_field.widget.attrs['data-images'] = json.dumps(images_map)\n\n    def get_variant(self, cleaned_data):\n        return cleaned_data.get('variant')\n\n", "path": "saleor/product/forms.py"}], "after_files": [{"content": "import datetime\nimport json\n\nfrom django.conf import settings\nfrom django.http import HttpResponsePermanentRedirect, JsonResponse\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.urls import reverse\n\nfrom ..cart.utils import set_cart_cookie\nfrom ..core.utils import get_paginator_items, serialize_decimal\nfrom ..core.utils.filters import get_now_sorted_by, get_sort_by_choices\nfrom .filters import ProductFilter, SORT_BY_FIELDS\nfrom .models import Category\nfrom .utils import (\n    get_availability, get_product_attributes_data, get_product_images,\n    get_variant_picker_data, handle_cart_form, product_json_ld,\n    products_for_cart, products_with_availability, products_with_details)\n\n\ndef product_details(request, slug, product_id, form=None):\n    \"\"\"Product details page\n\n    The following variables are available to the template:\n\n    product:\n        The Product instance itself.\n\n    is_visible:\n        Whether the product is visible to regular users (for cases when an\n        admin is previewing a product before publishing).\n\n    form:\n        The add-to-cart form.\n\n    price_range:\n        The PriceRange for the product including all discounts.\n\n    undiscounted_price_range:\n        The PriceRange excluding all discounts.\n\n    discount:\n        Either a Price instance equal to the discount value or None if no\n        discount was available.\n\n    local_price_range:\n        The same PriceRange from price_range represented in user's local\n        currency. The value will be None if exchange rate is not available or\n        the local currency is the same as site's default currency.\n    \"\"\"\n    products = products_with_details(user=request.user)\n    product = get_object_or_404(products, id=product_id)\n    if product.get_slug() != slug:\n        return HttpResponsePermanentRedirect(product.get_absolute_url())\n    today = datetime.date.today()\n    is_visible = (\n        product.available_on is None or product.available_on <= today)\n    if form is None:\n        form = handle_cart_form(request, product, create_cart=False)[0]\n    availability = get_availability(product, discounts=request.discounts,\n                                    local_currency=request.currency)\n    product_images = get_product_images(product)\n    variant_picker_data = get_variant_picker_data(\n        product, request.discounts, request.currency)\n    product_attributes = get_product_attributes_data(product)\n    # show_variant_picker determines if variant picker is used or select input\n    show_variant_picker = all([v.attributes for v in product.variants.all()])\n    json_ld_data = product_json_ld(product, availability, product_attributes)\n    return TemplateResponse(\n        request, 'product/details.html',\n        {'is_visible': is_visible,\n         'form': form,\n         'availability': availability,\n         'product': product,\n         'product_attributes': product_attributes,\n         'product_images': product_images,\n         'show_variant_picker': show_variant_picker,\n         'variant_picker_data': json.dumps(\n             variant_picker_data, default=serialize_decimal),\n         'json_ld_product_data': json.dumps(\n             json_ld_data, default=serialize_decimal)})\n\n\ndef product_add_to_cart(request, slug, product_id):\n    # types: (int, str, dict) -> None\n\n    if not request.method == 'POST':\n        return redirect(reverse(\n            'product:details',\n            kwargs={'product_id': product_id, 'slug': slug}))\n\n    products = products_for_cart(user=request.user)\n    product = get_object_or_404(products, pk=product_id)\n    form, cart = handle_cart_form(request, product, create_cart=True)\n    if form.is_valid():\n        form.save()\n        if request.is_ajax():\n            response = JsonResponse({'next': reverse('cart:index')}, status=200)\n        else:\n            response = redirect('cart:index')\n    else:\n        if request.is_ajax():\n            response = JsonResponse({'error': form.errors}, status=400)\n        else:\n            response = product_details(request, slug, product_id, form)\n    if not request.user.is_authenticated:\n        set_cart_cookie(cart, response)\n    return response\n\n\ndef category_index(request, path, category_id):\n    category = get_object_or_404(Category, id=category_id)\n    actual_path = category.get_full_path()\n    if actual_path != path:\n        return redirect('product:category', permanent=True, path=actual_path,\n                        category_id=category_id)\n    products = (products_with_details(user=request.user)\n                .filter(categories__id=category.id)\n                .order_by('name'))\n    product_filter = ProductFilter(\n        request.GET, queryset=products, category=category)\n    products_paginated = get_paginator_items(\n        product_filter.qs, settings.PAGINATE_BY, request.GET.get('page'))\n    products_and_availability = list(products_with_availability(\n        products_paginated, request.discounts, request.currency))\n    now_sorted_by = get_now_sorted_by(product_filter)\n    arg_sort_by = request.GET.get('sort_by')\n    is_descending = arg_sort_by.startswith('-') if arg_sort_by else False\n    ctx = {'category': category, 'filter_set': product_filter,\n           'products': products_and_availability,\n           'products_paginated': products_paginated,\n           'sort_by_choices': get_sort_by_choices(product_filter),\n           'now_sorted_by': now_sorted_by,\n           'is_descending': is_descending}\n    return TemplateResponse(request, 'category/index.html', ctx)\n", "path": "saleor/product/views.py"}, {"content": "import json\n\nfrom django import forms\nfrom django.utils.encoding import smart_text\nfrom django.utils.translation import pgettext_lazy\nfrom django_prices.templatetags.prices_i18n import gross\n\nfrom ..cart.forms import AddToCartForm\n\n\nclass VariantChoiceField(forms.ModelChoiceField):\n    discounts = None\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n    def label_from_instance(self, obj):\n        variant_label = smart_text(obj)\n        label = pgettext_lazy(\n            'Variant choice field label',\n            '%(variant_label)s - %(price)s') % {\n                'variant_label': variant_label,\n                'price': gross(obj.get_price(discounts=self.discounts))}\n        return label\n\n    def update_field_data(self, variants, cart):\n        \"\"\" Function initializing fields custom data \"\"\"\n        self.queryset = variants\n        self.discounts = cart.discounts\n        self.empty_label = None\n        images_map = {variant.pk: [vi.image.image.url\n                                   for vi in variant.variant_images.all()]\n                      for variant in variants.all()}\n        self.widget.attrs['data-images'] = json.dumps(images_map)\n        # Don't display select input if there are less than two variants\n        if self.queryset.count() < 2:\n            self.widget = forms.HiddenInput(\n                {'value': variants.all()[0].pk})\n\n\nclass ProductForm(AddToCartForm):\n    variant = VariantChoiceField(queryset=None)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        variant_field = self.fields['variant']\n        variant_field.update_field_data(self.product.variants, self.cart)\n\n    def get_variant(self, cleaned_data):\n        return cleaned_data.get('variant')\n", "path": "saleor/product/forms.py"}]}