Coverage for src/products/mixins.py: 100%
27 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-08-04 12:59 +0300
« prev ^ index » next coverage.py v7.9.2, created at 2025-08-04 12:59 +0300
1from django.db import models
2from django.db.models import Q
3from src.products.constants import NameFieldLengths
6class NameFieldMixin(models.Model):
7 """
8 Mixin class that provides a standardized name field for various entities.
10 This mixin is used by entities like Collection, Color, Metal, Stone, and Size
11 to ensure they all have a consistent name field with the same constraints.
12 Using a mixin instead of repeating the field definition in each model
13 promotes DRY (Don't Repeat Yourself) principles and makes maintenance easier.
15 The mixin uses the NAME_MAX_LENGTH constant from the constants module,
16 ensuring consistency across the application.
17 """
19 NAME_MAX_LENGTH = NameFieldLengths.NAME_MAX_LENGTH
21 class Meta:
22 abstract = True
24 # Standardized name field used across multiple entities
25 name = models.CharField(
26 max_length=NAME_MAX_LENGTH,
27 unique=True,
28 )
30 def __str__(self):
31 return self.name
34class FilterMixin:
35 """
36 Mixin class that provides filtering functionality for product listings.
38 This mixin is used by views that need to filter products based on
39 various attributes like colors, stones, metals, and collections.
40 It provides methods to extract filter parameters from request query
41 strings and build database queries.
43 The mixin supports both filtering by product attributes directly
44 and filtering by related inventory attributes.
45 """
47 def _get_params(self):
48 """
49 Extract filter parameters from the request query string.
51 This method looks for specific query parameters in the request
52 and returns them as a dictionary. The parameters are expected
53 to be lists (multiple values can be selected for each filter).
54 """
55 return {
56 'colors': self.request.query_params.getlist('colors'),
57 'stones': self.request.query_params.getlist('stones'),
58 'metals': self.request.query_params.getlist('metals'),
59 'collections': self.request.query_params.getlist('collections'),
60 }
62 def _build_filters(self, params, filter_map):
63 """
64 Build database filters based on provided parameters and filter mapping.
65 """
66 filters = Q()
68 for key, value in params.items():
69 if value and key in filter_map:
70 filters &= Q(**{filter_map[key]: value})
72 return filters
74 def _get_filters_for_attributes(self, category):
75 """
76 Build database filters for attribute-based filtering.
77 """
78 params = self._get_params()
80 filter_map = {
81 'colors': f'{category}__color_id__in',
82 'stones': f'{category}__stone_id__in',
83 'metals': f'{category}__metal_id__in',
84 'collections': f'{category}__collection_id__in',
85 }
87 return self._build_filters(params, filter_map)
89 def _get_filters_for_product(self):
90 """
91 Build database filters for direct product filtering.
92 """
93 params = self._get_params()
95 filter_map = {
96 'colors': 'color_id__in',
97 'stones': 'stone_id__in',
98 'metals': 'metal__id__in',
99 'collections': 'collection__id__in',
100 }
102 return self._build_filters(params, filter_map)