We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Problem with filtering products
### What I'm trying to achieve
I want to filter out products from grocerries category but I receive results even when I should not.

### Steps to reproduce the problem
In groceries category there are two beers that have `abv` attribute with values: 51(5,1% alc) and 67(6,75 alc) but when filter with `abv` value set to 52 we receive `Carrot juice` 

Correct query:
```
query{	
  products(first: 100, attributes: ["abv:51"]){
  	edges {
      node {
        id
        name
      }
    }
  }
}
```
and correct result:
```
{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "id": "UHJvZHVjdDo4Mw==",
            "name": "Seaman Lager"
          }
        }
      ]
    }
  }
}
```

Query with invalid value(abv set to 52):
```
query{	
  products(first: 100, attributes: ["abv:52"]){
  	edges {
      node {
        id
        name
      }
    }
  }
}
```
invalid result:
```
{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "id": "UHJvZHVjdDo3Mw==",
            "name": "Carrot Juice"
          }
        }
      ]
    }
  }
}
```

### What I expected to happen
We should receive empty product list if passing abv value 52.

--- 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/graphql/product/filters.py`
Content:
```
1 from collections import defaultdict
2 
3 import django_filters
4 from django.db.models import Q, Sum
5 from graphene_django.filter import GlobalIDFilter, GlobalIDMultipleChoiceFilter
6 
7 from ...product.filters import (
8     T_PRODUCT_FILTER_QUERIES,
9     filter_products_by_attributes_values,
10 )
11 from ...product.models import Attribute, Category, Collection, Product, ProductType
12 from ...search.backends import picker
13 from ..core.filters import EnumFilter, ListObjectTypeFilter, ObjectTypeFilter
14 from ..core.types import FilterInputObjectType
15 from ..core.types.common import PriceRangeInput
16 from ..core.utils import from_global_id_strict_type
17 from ..utils import filter_by_query_param, get_nodes
18 from . import types
19 from .enums import (
20     CollectionPublished,
21     ProductTypeConfigurable,
22     ProductTypeEnum,
23     StockAvailability,
24 )
25 from .types.attributes import AttributeInput
26 
27 
28 def filter_fields_containing_value(*search_fields: str):
29     """Create a icontains filters through given fields on a given query set object."""
30 
31     def _filter_qs(qs, _, value):
32         if value:
33             qs = filter_by_query_param(qs, value, search_fields)
34         return qs
35 
36     return _filter_qs
37 
38 
39 def _clean_product_attributes_filter_input(filter_value) -> T_PRODUCT_FILTER_QUERIES:
40     attributes = Attribute.objects.prefetch_related("values")
41     attributes_map = {attribute.slug: attribute.pk for attribute in attributes}
42     values_map = {
43         attr.slug: {value.slug: value.pk for value in attr.values.all()}
44         for attr in attributes
45     }
46     queries = defaultdict(list)
47 
48     # Convert attribute:value pairs into a dictionary where
49     # attributes are keys and values are grouped in lists
50     for attr_name, val_slug in filter_value:
51         if attr_name not in attributes_map:
52             raise ValueError("Unknown attribute name: %r" % (attr_name,))
53         attr_pk = attributes_map[attr_name]
54         attr_val_pk = values_map[attr_name].get(val_slug, val_slug)
55         queries[attr_pk].append(attr_val_pk)
56 
57     return queries
58 
59 
60 def filter_products_by_attributes(qs, filter_value):
61     queries = _clean_product_attributes_filter_input(filter_value)
62     return filter_products_by_attributes_values(qs, queries)
63 
64 
65 def filter_products_by_price(qs, price_lte=None, price_gte=None):
66     if price_lte:
67         qs = qs.filter(price_amount__lte=price_lte)
68     if price_gte:
69         qs = qs.filter(price_amount__gte=price_gte)
70     return qs
71 
72 
73 def filter_products_by_minimal_price(
74     qs, minimal_price_lte=None, minimal_price_gte=None
75 ):
76     if minimal_price_lte:
77         qs = qs.filter(minimal_variant_price_amount__lte=minimal_price_lte)
78     if minimal_price_gte:
79         qs = qs.filter(minimal_variant_price_amount__gte=minimal_price_gte)
80     return qs
81 
82 
83 def filter_products_by_categories(qs, categories):
84     categories = [
85         category.get_descendants(include_self=True) for category in categories
86     ]
87     ids = {category.id for tree in categories for category in tree}
88     return qs.filter(category__in=ids)
89 
90 
91 def filter_products_by_collections(qs, collections):
92     return qs.filter(collections__in=collections)
93 
94 
95 def sort_qs(qs, sort_by):
96     if sort_by:
97         qs = qs.order_by(sort_by["direction"] + sort_by["field"])
98     return qs
99 
100 
101 def filter_products_by_stock_availability(qs, stock_availability):
102     qs = qs.annotate(total_quantity=Sum("variants__quantity"))
103     if stock_availability == StockAvailability.IN_STOCK:
104         qs = qs.filter(total_quantity__gt=0)
105     elif stock_availability == StockAvailability.OUT_OF_STOCK:
106         qs = qs.filter(total_quantity=0)
107     return qs
108 
109 
110 def filter_attributes(qs, _, value):
111     if value:
112         value = [(v["slug"], v["value"]) for v in value]
113         qs = filter_products_by_attributes(qs, value)
114     return qs
115 
116 
117 def filter_categories(qs, _, value):
118     if value:
119         categories = get_nodes(value, types.Category)
120         qs = filter_products_by_categories(qs, categories)
121     return qs
122 
123 
124 def filter_collections(qs, _, value):
125     if value:
126         collections = get_nodes(value, types.Collection)
127         qs = filter_products_by_collections(qs, collections)
128     return qs
129 
130 
131 def filter_price(qs, _, value):
132     qs = filter_products_by_price(
133         qs, price_lte=value.get("lte"), price_gte=value.get("gte")
134     )
135     return qs
136 
137 
138 def filter_minimal_price(qs, _, value):
139     qs = filter_products_by_minimal_price(
140         qs, minimal_price_lte=value.get("lte"), minimal_price_gte=value.get("gte")
141     )
142     return qs
143 
144 
145 def filter_stock_availability(qs, _, value):
146     if value:
147         qs = filter_products_by_stock_availability(qs, value)
148     return qs
149 
150 
151 def filter_search(qs, _, value):
152     if value:
153         search = picker.pick_backend()
154         qs &= search(value).distinct()
155     return qs
156 
157 
158 def filter_collection_publish(qs, _, value):
159     if value == CollectionPublished.PUBLISHED:
160         qs = qs.filter(is_published=True)
161     elif value == CollectionPublished.HIDDEN:
162         qs = qs.filter(is_published=False)
163     return qs
164 
165 
166 def filter_product_type_configurable(qs, _, value):
167     if value == ProductTypeConfigurable.CONFIGURABLE:
168         qs = qs.filter(has_variants=True)
169     elif value == ProductTypeConfigurable.SIMPLE:
170         qs = qs.filter(has_variants=False)
171     return qs
172 
173 
174 def filter_product_type(qs, _, value):
175     if value == ProductTypeEnum.DIGITAL:
176         qs = qs.filter(is_digital=True)
177     elif value == ProductTypeEnum.SHIPPABLE:
178         qs = qs.filter(is_shipping_required=True)
179     return qs
180 
181 
182 def filter_attributes_by_product_types(qs, field, value):
183     if not value:
184         return qs
185 
186     if field == "in_category":
187         category_id = from_global_id_strict_type(
188             value, only_type="Category", field=field
189         )
190         category = Category.objects.filter(pk=category_id).first()
191 
192         if category is None:
193             return qs.none()
194 
195         tree = category.get_descendants(include_self=True)
196         product_qs = Product.objects.filter(category__in=tree)
197 
198     elif field == "in_collection":
199         collection_id = from_global_id_strict_type(
200             value, only_type="Collection", field=field
201         )
202         product_qs = Product.objects.filter(collections__id=collection_id)
203 
204     else:
205         raise NotImplementedError(f"Filtering by {field} is unsupported")
206 
207     product_types = set(product_qs.values_list("product_type_id", flat=True))
208     return qs.filter(
209         Q(product_types__in=product_types) | Q(product_variant_types__in=product_types)
210     )
211 
212 
213 class ProductFilter(django_filters.FilterSet):
214     is_published = django_filters.BooleanFilter()
215     collections = GlobalIDMultipleChoiceFilter(method=filter_collections)
216     categories = GlobalIDMultipleChoiceFilter(method=filter_categories)
217     price = ObjectTypeFilter(
218         input_class=PriceRangeInput, method=filter_price, field_name="price_amount"
219     )
220     minimal_price = ObjectTypeFilter(
221         input_class=PriceRangeInput,
222         method=filter_minimal_price,
223         field_name="minimal_price_amount",
224     )
225     attributes = ListObjectTypeFilter(
226         input_class=AttributeInput, method=filter_attributes
227     )
228     stock_availability = EnumFilter(
229         input_class=StockAvailability, method=filter_stock_availability
230     )
231     product_type = GlobalIDFilter()
232     search = django_filters.CharFilter(method=filter_search)
233 
234     class Meta:
235         model = Product
236         fields = [
237             "is_published",
238             "collections",
239             "categories",
240             "price",
241             "attributes",
242             "stock_availability",
243             "product_type",
244             "search",
245         ]
246 
247 
248 class CollectionFilter(django_filters.FilterSet):
249     published = EnumFilter(
250         input_class=CollectionPublished, method=filter_collection_publish
251     )
252     search = django_filters.CharFilter(
253         method=filter_fields_containing_value("slug", "name")
254     )
255 
256     class Meta:
257         model = Collection
258         fields = ["published", "search"]
259 
260 
261 class CategoryFilter(django_filters.FilterSet):
262     search = django_filters.CharFilter(
263         method=filter_fields_containing_value("slug", "name", "description")
264     )
265 
266     class Meta:
267         model = Category
268         fields = ["search"]
269 
270 
271 class ProductTypeFilter(django_filters.FilterSet):
272     search = django_filters.CharFilter(method=filter_fields_containing_value("name"))
273 
274     configurable = EnumFilter(
275         input_class=ProductTypeConfigurable, method=filter_product_type_configurable
276     )
277 
278     product_type = EnumFilter(input_class=ProductTypeEnum, method=filter_product_type)
279 
280     class Meta:
281         model = ProductType
282         fields = ["search", "configurable", "product_type"]
283 
284 
285 class AttributeFilter(django_filters.FilterSet):
286     # Search by attribute name and slug
287     search = django_filters.CharFilter(
288         method=filter_fields_containing_value("slug", "name")
289     )
290     ids = GlobalIDMultipleChoiceFilter(field_name="id")
291 
292     in_collection = GlobalIDFilter(method=filter_attributes_by_product_types)
293     in_category = GlobalIDFilter(method=filter_attributes_by_product_types)
294 
295     class Meta:
296         model = Attribute
297         fields = [
298             "value_required",
299             "is_variant_only",
300             "visible_in_storefront",
301             "filterable_in_storefront",
302             "filterable_in_dashboard",
303             "available_in_grid",
304         ]
305 
306 
307 class ProductFilterInput(FilterInputObjectType):
308     class Meta:
309         filterset_class = ProductFilter
310 
311 
312 class CollectionFilterInput(FilterInputObjectType):
313     class Meta:
314         filterset_class = CollectionFilter
315 
316 
317 class CategoryFilterInput(FilterInputObjectType):
318     class Meta:
319         filterset_class = CategoryFilter
320 
321 
322 class ProductTypeFilterInput(FilterInputObjectType):
323     class Meta:
324         filterset_class = ProductTypeFilter
325 
326 
327 class AttributeFilterInput(FilterInputObjectType):
328     class Meta:
329         filterset_class = AttributeFilter
330
```
--- 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/graphql/product/filters.py b/saleor/graphql/product/filters.py
--- a/saleor/graphql/product/filters.py
+++ b/saleor/graphql/product/filters.py
@@ -51,7 +51,7 @@
         if attr_name not in attributes_map:
             raise ValueError("Unknown attribute name: %r" % (attr_name,))
         attr_pk = attributes_map[attr_name]
-        attr_val_pk = values_map[attr_name].get(val_slug, val_slug)
+        attr_val_pk = values_map[attr_name].get(val_slug)
         queries[attr_pk].append(attr_val_pk)
 
     return queries

{"golden_diff": "diff --git a/saleor/graphql/product/filters.py b/saleor/graphql/product/filters.py\n--- a/saleor/graphql/product/filters.py\n+++ b/saleor/graphql/product/filters.py\n@@ -51,7 +51,7 @@\n         if attr_name not in attributes_map:\n             raise ValueError(\"Unknown attribute name: %r\" % (attr_name,))\n         attr_pk = attributes_map[attr_name]\n-        attr_val_pk = values_map[attr_name].get(val_slug, val_slug)\n+        attr_val_pk = values_map[attr_name].get(val_slug)\n         queries[attr_pk].append(attr_val_pk)\n \n     return queries\n", "issue": "Problem with filtering products\n### What I'm trying to achieve\r\nI want to filter out products from grocerries category but I receive results even when I should not.\r\n\r\n### Steps to reproduce the problem\r\nIn groceries category there are two beers that have `abv` attribute with values: 51(5,1% alc) and 67(6,75 alc) but when filter with `abv` value set to 52 we receive `Carrot juice` \r\n\r\nCorrect query:\r\n```\r\nquery{\t\r\n  products(first: 100, attributes: [\"abv:51\"]){\r\n  \tedges {\r\n      node {\r\n        id\r\n        name\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\nand correct result:\r\n```\r\n{\r\n  \"data\": {\r\n    \"products\": {\r\n      \"edges\": [\r\n        {\r\n          \"node\": {\r\n            \"id\": \"UHJvZHVjdDo4Mw==\",\r\n            \"name\": \"Seaman Lager\"\r\n          }\r\n        }\r\n      ]\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nQuery with invalid value(abv set to 52):\r\n```\r\nquery{\t\r\n  products(first: 100, attributes: [\"abv:52\"]){\r\n  \tedges {\r\n      node {\r\n        id\r\n        name\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\ninvalid result:\r\n```\r\n{\r\n  \"data\": {\r\n    \"products\": {\r\n      \"edges\": [\r\n        {\r\n          \"node\": {\r\n            \"id\": \"UHJvZHVjdDo3Mw==\",\r\n            \"name\": \"Carrot Juice\"\r\n          }\r\n        }\r\n      ]\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### What I expected to happen\r\nWe should receive empty product list if passing abv value 52.\n", "before_files": [{"content": "from collections import defaultdict\n\nimport django_filters\nfrom django.db.models import Q, Sum\nfrom graphene_django.filter import GlobalIDFilter, GlobalIDMultipleChoiceFilter\n\nfrom ...product.filters import (\n    T_PRODUCT_FILTER_QUERIES,\n    filter_products_by_attributes_values,\n)\nfrom ...product.models import Attribute, Category, Collection, Product, ProductType\nfrom ...search.backends import picker\nfrom ..core.filters import EnumFilter, ListObjectTypeFilter, ObjectTypeFilter\nfrom ..core.types import FilterInputObjectType\nfrom ..core.types.common import PriceRangeInput\nfrom ..core.utils import from_global_id_strict_type\nfrom ..utils import filter_by_query_param, get_nodes\nfrom . import types\nfrom .enums import (\n    CollectionPublished,\n    ProductTypeConfigurable,\n    ProductTypeEnum,\n    StockAvailability,\n)\nfrom .types.attributes import AttributeInput\n\n\ndef filter_fields_containing_value(*search_fields: str):\n    \"\"\"Create a icontains filters through given fields on a given query set object.\"\"\"\n\n    def _filter_qs(qs, _, value):\n        if value:\n            qs = filter_by_query_param(qs, value, search_fields)\n        return qs\n\n    return _filter_qs\n\n\ndef _clean_product_attributes_filter_input(filter_value) -> T_PRODUCT_FILTER_QUERIES:\n    attributes = Attribute.objects.prefetch_related(\"values\")\n    attributes_map = {attribute.slug: attribute.pk for attribute in attributes}\n    values_map = {\n        attr.slug: {value.slug: value.pk for value in attr.values.all()}\n        for attr in attributes\n    }\n    queries = defaultdict(list)\n\n    # Convert attribute:value pairs into a dictionary where\n    # attributes are keys and values are grouped in lists\n    for attr_name, val_slug in filter_value:\n        if attr_name not in attributes_map:\n            raise ValueError(\"Unknown attribute name: %r\" % (attr_name,))\n        attr_pk = attributes_map[attr_name]\n        attr_val_pk = values_map[attr_name].get(val_slug, val_slug)\n        queries[attr_pk].append(attr_val_pk)\n\n    return queries\n\n\ndef filter_products_by_attributes(qs, filter_value):\n    queries = _clean_product_attributes_filter_input(filter_value)\n    return filter_products_by_attributes_values(qs, queries)\n\n\ndef filter_products_by_price(qs, price_lte=None, price_gte=None):\n    if price_lte:\n        qs = qs.filter(price_amount__lte=price_lte)\n    if price_gte:\n        qs = qs.filter(price_amount__gte=price_gte)\n    return qs\n\n\ndef filter_products_by_minimal_price(\n    qs, minimal_price_lte=None, minimal_price_gte=None\n):\n    if minimal_price_lte:\n        qs = qs.filter(minimal_variant_price_amount__lte=minimal_price_lte)\n    if minimal_price_gte:\n        qs = qs.filter(minimal_variant_price_amount__gte=minimal_price_gte)\n    return qs\n\n\ndef filter_products_by_categories(qs, categories):\n    categories = [\n        category.get_descendants(include_self=True) for category in categories\n    ]\n    ids = {category.id for tree in categories for category in tree}\n    return qs.filter(category__in=ids)\n\n\ndef filter_products_by_collections(qs, collections):\n    return qs.filter(collections__in=collections)\n\n\ndef sort_qs(qs, sort_by):\n    if sort_by:\n        qs = qs.order_by(sort_by[\"direction\"] + sort_by[\"field\"])\n    return qs\n\n\ndef filter_products_by_stock_availability(qs, stock_availability):\n    qs = qs.annotate(total_quantity=Sum(\"variants__quantity\"))\n    if stock_availability == StockAvailability.IN_STOCK:\n        qs = qs.filter(total_quantity__gt=0)\n    elif stock_availability == StockAvailability.OUT_OF_STOCK:\n        qs = qs.filter(total_quantity=0)\n    return qs\n\n\ndef filter_attributes(qs, _, value):\n    if value:\n        value = [(v[\"slug\"], v[\"value\"]) for v in value]\n        qs = filter_products_by_attributes(qs, value)\n    return qs\n\n\ndef filter_categories(qs, _, value):\n    if value:\n        categories = get_nodes(value, types.Category)\n        qs = filter_products_by_categories(qs, categories)\n    return qs\n\n\ndef filter_collections(qs, _, value):\n    if value:\n        collections = get_nodes(value, types.Collection)\n        qs = filter_products_by_collections(qs, collections)\n    return qs\n\n\ndef filter_price(qs, _, value):\n    qs = filter_products_by_price(\n        qs, price_lte=value.get(\"lte\"), price_gte=value.get(\"gte\")\n    )\n    return qs\n\n\ndef filter_minimal_price(qs, _, value):\n    qs = filter_products_by_minimal_price(\n        qs, minimal_price_lte=value.get(\"lte\"), minimal_price_gte=value.get(\"gte\")\n    )\n    return qs\n\n\ndef filter_stock_availability(qs, _, value):\n    if value:\n        qs = filter_products_by_stock_availability(qs, value)\n    return qs\n\n\ndef filter_search(qs, _, value):\n    if value:\n        search = picker.pick_backend()\n        qs &= search(value).distinct()\n    return qs\n\n\ndef filter_collection_publish(qs, _, value):\n    if value == CollectionPublished.PUBLISHED:\n        qs = qs.filter(is_published=True)\n    elif value == CollectionPublished.HIDDEN:\n        qs = qs.filter(is_published=False)\n    return qs\n\n\ndef filter_product_type_configurable(qs, _, value):\n    if value == ProductTypeConfigurable.CONFIGURABLE:\n        qs = qs.filter(has_variants=True)\n    elif value == ProductTypeConfigurable.SIMPLE:\n        qs = qs.filter(has_variants=False)\n    return qs\n\n\ndef filter_product_type(qs, _, value):\n    if value == ProductTypeEnum.DIGITAL:\n        qs = qs.filter(is_digital=True)\n    elif value == ProductTypeEnum.SHIPPABLE:\n        qs = qs.filter(is_shipping_required=True)\n    return qs\n\n\ndef filter_attributes_by_product_types(qs, field, value):\n    if not value:\n        return qs\n\n    if field == \"in_category\":\n        category_id = from_global_id_strict_type(\n            value, only_type=\"Category\", field=field\n        )\n        category = Category.objects.filter(pk=category_id).first()\n\n        if category is None:\n            return qs.none()\n\n        tree = category.get_descendants(include_self=True)\n        product_qs = Product.objects.filter(category__in=tree)\n\n    elif field == \"in_collection\":\n        collection_id = from_global_id_strict_type(\n            value, only_type=\"Collection\", field=field\n        )\n        product_qs = Product.objects.filter(collections__id=collection_id)\n\n    else:\n        raise NotImplementedError(f\"Filtering by {field} is unsupported\")\n\n    product_types = set(product_qs.values_list(\"product_type_id\", flat=True))\n    return qs.filter(\n        Q(product_types__in=product_types) | Q(product_variant_types__in=product_types)\n    )\n\n\nclass ProductFilter(django_filters.FilterSet):\n    is_published = django_filters.BooleanFilter()\n    collections = GlobalIDMultipleChoiceFilter(method=filter_collections)\n    categories = GlobalIDMultipleChoiceFilter(method=filter_categories)\n    price = ObjectTypeFilter(\n        input_class=PriceRangeInput, method=filter_price, field_name=\"price_amount\"\n    )\n    minimal_price = ObjectTypeFilter(\n        input_class=PriceRangeInput,\n        method=filter_minimal_price,\n        field_name=\"minimal_price_amount\",\n    )\n    attributes = ListObjectTypeFilter(\n        input_class=AttributeInput, method=filter_attributes\n    )\n    stock_availability = EnumFilter(\n        input_class=StockAvailability, method=filter_stock_availability\n    )\n    product_type = GlobalIDFilter()\n    search = django_filters.CharFilter(method=filter_search)\n\n    class Meta:\n        model = Product\n        fields = [\n            \"is_published\",\n            \"collections\",\n            \"categories\",\n            \"price\",\n            \"attributes\",\n            \"stock_availability\",\n            \"product_type\",\n            \"search\",\n        ]\n\n\nclass CollectionFilter(django_filters.FilterSet):\n    published = EnumFilter(\n        input_class=CollectionPublished, method=filter_collection_publish\n    )\n    search = django_filters.CharFilter(\n        method=filter_fields_containing_value(\"slug\", \"name\")\n    )\n\n    class Meta:\n        model = Collection\n        fields = [\"published\", \"search\"]\n\n\nclass CategoryFilter(django_filters.FilterSet):\n    search = django_filters.CharFilter(\n        method=filter_fields_containing_value(\"slug\", \"name\", \"description\")\n    )\n\n    class Meta:\n        model = Category\n        fields = [\"search\"]\n\n\nclass ProductTypeFilter(django_filters.FilterSet):\n    search = django_filters.CharFilter(method=filter_fields_containing_value(\"name\"))\n\n    configurable = EnumFilter(\n        input_class=ProductTypeConfigurable, method=filter_product_type_configurable\n    )\n\n    product_type = EnumFilter(input_class=ProductTypeEnum, method=filter_product_type)\n\n    class Meta:\n        model = ProductType\n        fields = [\"search\", \"configurable\", \"product_type\"]\n\n\nclass AttributeFilter(django_filters.FilterSet):\n    # Search by attribute name and slug\n    search = django_filters.CharFilter(\n        method=filter_fields_containing_value(\"slug\", \"name\")\n    )\n    ids = GlobalIDMultipleChoiceFilter(field_name=\"id\")\n\n    in_collection = GlobalIDFilter(method=filter_attributes_by_product_types)\n    in_category = GlobalIDFilter(method=filter_attributes_by_product_types)\n\n    class Meta:\n        model = Attribute\n        fields = [\n            \"value_required\",\n            \"is_variant_only\",\n            \"visible_in_storefront\",\n            \"filterable_in_storefront\",\n            \"filterable_in_dashboard\",\n            \"available_in_grid\",\n        ]\n\n\nclass ProductFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = ProductFilter\n\n\nclass CollectionFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = CollectionFilter\n\n\nclass CategoryFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = CategoryFilter\n\n\nclass ProductTypeFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = ProductTypeFilter\n\n\nclass AttributeFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = AttributeFilter\n", "path": "saleor/graphql/product/filters.py"}], "after_files": [{"content": "from collections import defaultdict\n\nimport django_filters\nfrom django.db.models import Q, Sum\nfrom graphene_django.filter import GlobalIDFilter, GlobalIDMultipleChoiceFilter\n\nfrom ...product.filters import (\n    T_PRODUCT_FILTER_QUERIES,\n    filter_products_by_attributes_values,\n)\nfrom ...product.models import Attribute, Category, Collection, Product, ProductType\nfrom ...search.backends import picker\nfrom ..core.filters import EnumFilter, ListObjectTypeFilter, ObjectTypeFilter\nfrom ..core.types import FilterInputObjectType\nfrom ..core.types.common import PriceRangeInput\nfrom ..core.utils import from_global_id_strict_type\nfrom ..utils import filter_by_query_param, get_nodes\nfrom . import types\nfrom .enums import (\n    CollectionPublished,\n    ProductTypeConfigurable,\n    ProductTypeEnum,\n    StockAvailability,\n)\nfrom .types.attributes import AttributeInput\n\n\ndef filter_fields_containing_value(*search_fields: str):\n    \"\"\"Create a icontains filters through given fields on a given query set object.\"\"\"\n\n    def _filter_qs(qs, _, value):\n        if value:\n            qs = filter_by_query_param(qs, value, search_fields)\n        return qs\n\n    return _filter_qs\n\n\ndef _clean_product_attributes_filter_input(filter_value) -> T_PRODUCT_FILTER_QUERIES:\n    attributes = Attribute.objects.prefetch_related(\"values\")\n    attributes_map = {attribute.slug: attribute.pk for attribute in attributes}\n    values_map = {\n        attr.slug: {value.slug: value.pk for value in attr.values.all()}\n        for attr in attributes\n    }\n    queries = defaultdict(list)\n\n    # Convert attribute:value pairs into a dictionary where\n    # attributes are keys and values are grouped in lists\n    for attr_name, val_slug in filter_value:\n        if attr_name not in attributes_map:\n            raise ValueError(\"Unknown attribute name: %r\" % (attr_name,))\n        attr_pk = attributes_map[attr_name]\n        attr_val_pk = values_map[attr_name].get(val_slug)\n        queries[attr_pk].append(attr_val_pk)\n\n    return queries\n\n\ndef filter_products_by_attributes(qs, filter_value):\n    queries = _clean_product_attributes_filter_input(filter_value)\n    return filter_products_by_attributes_values(qs, queries)\n\n\ndef filter_products_by_price(qs, price_lte=None, price_gte=None):\n    if price_lte:\n        qs = qs.filter(price_amount__lte=price_lte)\n    if price_gte:\n        qs = qs.filter(price_amount__gte=price_gte)\n    return qs\n\n\ndef filter_products_by_minimal_price(\n    qs, minimal_price_lte=None, minimal_price_gte=None\n):\n    if minimal_price_lte:\n        qs = qs.filter(minimal_variant_price_amount__lte=minimal_price_lte)\n    if minimal_price_gte:\n        qs = qs.filter(minimal_variant_price_amount__gte=minimal_price_gte)\n    return qs\n\n\ndef filter_products_by_categories(qs, categories):\n    categories = [\n        category.get_descendants(include_self=True) for category in categories\n    ]\n    ids = {category.id for tree in categories for category in tree}\n    return qs.filter(category__in=ids)\n\n\ndef filter_products_by_collections(qs, collections):\n    return qs.filter(collections__in=collections)\n\n\ndef sort_qs(qs, sort_by):\n    if sort_by:\n        qs = qs.order_by(sort_by[\"direction\"] + sort_by[\"field\"])\n    return qs\n\n\ndef filter_products_by_stock_availability(qs, stock_availability):\n    qs = qs.annotate(total_quantity=Sum(\"variants__quantity\"))\n    if stock_availability == StockAvailability.IN_STOCK:\n        qs = qs.filter(total_quantity__gt=0)\n    elif stock_availability == StockAvailability.OUT_OF_STOCK:\n        qs = qs.filter(total_quantity=0)\n    return qs\n\n\ndef filter_attributes(qs, _, value):\n    if value:\n        value = [(v[\"slug\"], v[\"value\"]) for v in value]\n        qs = filter_products_by_attributes(qs, value)\n    return qs\n\n\ndef filter_categories(qs, _, value):\n    if value:\n        categories = get_nodes(value, types.Category)\n        qs = filter_products_by_categories(qs, categories)\n    return qs\n\n\ndef filter_collections(qs, _, value):\n    if value:\n        collections = get_nodes(value, types.Collection)\n        qs = filter_products_by_collections(qs, collections)\n    return qs\n\n\ndef filter_price(qs, _, value):\n    qs = filter_products_by_price(\n        qs, price_lte=value.get(\"lte\"), price_gte=value.get(\"gte\")\n    )\n    return qs\n\n\ndef filter_minimal_price(qs, _, value):\n    qs = filter_products_by_minimal_price(\n        qs, minimal_price_lte=value.get(\"lte\"), minimal_price_gte=value.get(\"gte\")\n    )\n    return qs\n\n\ndef filter_stock_availability(qs, _, value):\n    if value:\n        qs = filter_products_by_stock_availability(qs, value)\n    return qs\n\n\ndef filter_search(qs, _, value):\n    if value:\n        search = picker.pick_backend()\n        qs &= search(value).distinct()\n    return qs\n\n\ndef filter_collection_publish(qs, _, value):\n    if value == CollectionPublished.PUBLISHED:\n        qs = qs.filter(is_published=True)\n    elif value == CollectionPublished.HIDDEN:\n        qs = qs.filter(is_published=False)\n    return qs\n\n\ndef filter_product_type_configurable(qs, _, value):\n    if value == ProductTypeConfigurable.CONFIGURABLE:\n        qs = qs.filter(has_variants=True)\n    elif value == ProductTypeConfigurable.SIMPLE:\n        qs = qs.filter(has_variants=False)\n    return qs\n\n\ndef filter_product_type(qs, _, value):\n    if value == ProductTypeEnum.DIGITAL:\n        qs = qs.filter(is_digital=True)\n    elif value == ProductTypeEnum.SHIPPABLE:\n        qs = qs.filter(is_shipping_required=True)\n    return qs\n\n\ndef filter_attributes_by_product_types(qs, field, value):\n    if not value:\n        return qs\n\n    if field == \"in_category\":\n        category_id = from_global_id_strict_type(\n            value, only_type=\"Category\", field=field\n        )\n        category = Category.objects.filter(pk=category_id).first()\n\n        if category is None:\n            return qs.none()\n\n        tree = category.get_descendants(include_self=True)\n        product_qs = Product.objects.filter(category__in=tree)\n\n    elif field == \"in_collection\":\n        collection_id = from_global_id_strict_type(\n            value, only_type=\"Collection\", field=field\n        )\n        product_qs = Product.objects.filter(collections__id=collection_id)\n\n    else:\n        raise NotImplementedError(f\"Filtering by {field} is unsupported\")\n\n    product_types = set(product_qs.values_list(\"product_type_id\", flat=True))\n    return qs.filter(\n        Q(product_types__in=product_types) | Q(product_variant_types__in=product_types)\n    )\n\n\nclass ProductFilter(django_filters.FilterSet):\n    is_published = django_filters.BooleanFilter()\n    collections = GlobalIDMultipleChoiceFilter(method=filter_collections)\n    categories = GlobalIDMultipleChoiceFilter(method=filter_categories)\n    price = ObjectTypeFilter(\n        input_class=PriceRangeInput, method=filter_price, field_name=\"price_amount\"\n    )\n    minimal_price = ObjectTypeFilter(\n        input_class=PriceRangeInput,\n        method=filter_minimal_price,\n        field_name=\"minimal_price_amount\",\n    )\n    attributes = ListObjectTypeFilter(\n        input_class=AttributeInput, method=filter_attributes\n    )\n    stock_availability = EnumFilter(\n        input_class=StockAvailability, method=filter_stock_availability\n    )\n    product_type = GlobalIDFilter()\n    search = django_filters.CharFilter(method=filter_search)\n\n    class Meta:\n        model = Product\n        fields = [\n            \"is_published\",\n            \"collections\",\n            \"categories\",\n            \"price\",\n            \"attributes\",\n            \"stock_availability\",\n            \"product_type\",\n            \"search\",\n        ]\n\n\nclass CollectionFilter(django_filters.FilterSet):\n    published = EnumFilter(\n        input_class=CollectionPublished, method=filter_collection_publish\n    )\n    search = django_filters.CharFilter(\n        method=filter_fields_containing_value(\"slug\", \"name\")\n    )\n\n    class Meta:\n        model = Collection\n        fields = [\"published\", \"search\"]\n\n\nclass CategoryFilter(django_filters.FilterSet):\n    search = django_filters.CharFilter(\n        method=filter_fields_containing_value(\"slug\", \"name\", \"description\")\n    )\n\n    class Meta:\n        model = Category\n        fields = [\"search\"]\n\n\nclass ProductTypeFilter(django_filters.FilterSet):\n    search = django_filters.CharFilter(method=filter_fields_containing_value(\"name\"))\n\n    configurable = EnumFilter(\n        input_class=ProductTypeConfigurable, method=filter_product_type_configurable\n    )\n\n    product_type = EnumFilter(input_class=ProductTypeEnum, method=filter_product_type)\n\n    class Meta:\n        model = ProductType\n        fields = [\"search\", \"configurable\", \"product_type\"]\n\n\nclass AttributeFilter(django_filters.FilterSet):\n    # Search by attribute name and slug\n    search = django_filters.CharFilter(\n        method=filter_fields_containing_value(\"slug\", \"name\")\n    )\n    ids = GlobalIDMultipleChoiceFilter(field_name=\"id\")\n\n    in_collection = GlobalIDFilter(method=filter_attributes_by_product_types)\n    in_category = GlobalIDFilter(method=filter_attributes_by_product_types)\n\n    class Meta:\n        model = Attribute\n        fields = [\n            \"value_required\",\n            \"is_variant_only\",\n            \"visible_in_storefront\",\n            \"filterable_in_storefront\",\n            \"filterable_in_dashboard\",\n            \"available_in_grid\",\n        ]\n\n\nclass ProductFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = ProductFilter\n\n\nclass CollectionFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = CollectionFilter\n\n\nclass CategoryFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = CategoryFilter\n\n\nclass ProductTypeFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = ProductTypeFilter\n\n\nclass AttributeFilterInput(FilterInputObjectType):\n    class Meta:\n        filterset_class = AttributeFilter\n", "path": "saleor/graphql/product/filters.py"}]}