From d2fb27a2c3d78f26604299a0883fea4a5f3b247b Mon Sep 17 00:00:00 2001 From: mtyton Date: Thu, 10 Aug 2023 22:24:48 +0200 Subject: [PATCH 1/6] product load finally works --- .gitignore | 1 + artel/store/loader.py | 41 ++++++++++++------- .../management/commands/load_products.py | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index b809595..99e9fc6 100644 --- a/.gitignore +++ b/.gitignore @@ -143,3 +143,4 @@ artel/static/ # media artel/media/* +artel/store/data/* diff --git a/artel/store/loader.py b/artel/store/loader.py index 8174711..92f7938 100644 --- a/artel/store/loader.py +++ b/artel/store/loader.py @@ -1,12 +1,13 @@ import logging +import time import requests import pandas as pd -from django.core import files - +from django.core.files.base import ContentFile from store.models import ( ProductTemplate, ProductCategoryParamValue, + ProductCategoryParam, Product, ProductImage ) @@ -29,28 +30,37 @@ class TemplateLoader(BaseLoader): class ProductLoader(BaseLoader): - def _get_images(self, row) -> list[files.ContentFile]: - urls = row["images"] + def _clear(self): + Product.objects.all().delete() + + def __init__(self, path, param_names, clear=False): + super().__init__(path) + self.param_names = param_names + if clear: + self._clear() + + def _get_images(self, row) -> list[ContentFile]: + url = row["images"] images = [] - for url in urls: - response = requests.get(url, stream=True) - if response.status_code == 200: - data = response.raw - file_name = url.split("/")[-1] - image = files.ContentFile(data, name=file_name) + response = requests.get(url+"/download", stream=True) + print(response.status_code) + if response.status_code == 200: + data = response.content + image = ContentFile(data, name=row["template"]) images.append(image) return images def _process_row(self, row): template = ProductTemplate.objects.get(code=row["template"]) - price = float(row["price"]) + price = float(row["price"].strip("zł").replace(",", ".")) name = row["name"] available = bool(row["available"]) params = [] - for param in row["params"]: - key, value = param - param = ProductCategoryParamValue.objects.get(param__key=key, value=value) - params.append(param) + for key in self.param_names: + value = row[key] + param, _ = ProductCategoryParam.objects.get_or_create(key=key, category=template.category) + param_value, _ = ProductCategoryParamValue.objects.get_or_create(param=param, value=value) + params.append(param_value) product = Product.objects.get_or_create_by_params(template=template, params=params) product.price = price product.name = name @@ -66,6 +76,7 @@ class ProductLoader(BaseLoader): data = self.load_data() products = [] for _, row in data.iterrows(): + time.sleep(5) try: product = self._process_row(row) except Exception as e: diff --git a/artel/store/management/commands/load_products.py b/artel/store/management/commands/load_products.py index a277ad0..84197e0 100644 --- a/artel/store/management/commands/load_products.py +++ b/artel/store/management/commands/load_products.py @@ -9,5 +9,5 @@ class Command(BaseCommand): help = "Load products from csv file" def handle(self, *args, **options): - loader = ProductLoader(settings.PRODUCTS_CSV_PATH) + loader = ProductLoader(settings.PRODUCTS_CSV_PATH, ["mocowanie", "format", "wykonanie"], True) loader.process() From 74e8822a183f88caf8707355a8b3754b225df0dd Mon Sep 17 00:00:00 2001 From: mtyton Date: Thu, 10 Aug 2023 22:30:47 +0200 Subject: [PATCH 2/6] fixed form field generation --- artel/store/forms.py | 9 +++++++-- artel/store/models.py | 2 +- .../store/forms/button_toggle_select.html | 16 ---------------- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/artel/store/forms.py b/artel/store/forms.py index 64ab14f..8262828 100644 --- a/artel/store/forms.py +++ b/artel/store/forms.py @@ -73,9 +73,14 @@ class ProductTemplateConfigForm(forms.Form): def _create_dynamic_fields(self, template: ProductTemplate): category_params = template.category.category_params.all() for param in category_params: + queryset = ProductCategoryParamValue.objects.filter(param=param) + if queryset.count() >= 4: + widget = forms.Select(attrs={"class": "form-select"}) + else: + widget = ButtonToggleSelect(attrs={"class": "btn-group btn-group-toggle"}) self.fields[param.key] = forms.ModelChoiceField( - queryset=ProductCategoryParamValue.objects.filter(param=param), - widget=ButtonToggleSelect(attrs={"class": "btn-group btn-group-toggle"}), + queryset=queryset, + widget=widget, ) def __init__( diff --git a/artel/store/models.py b/artel/store/models.py index 2919cf9..3937692 100644 --- a/artel/store/models.py +++ b/artel/store/models.py @@ -133,7 +133,7 @@ class ProductCategoryParamValue(ClusterableModel): return def __str__(self): - return f"{self.param.key}: {self.value}" + return str(self.value) class ProductTemplate(ClusterableModel): diff --git a/artel/store/templates/store/forms/button_toggle_select.html b/artel/store/templates/store/forms/button_toggle_select.html index 2d5e4b6..b145705 100644 --- a/artel/store/templates/store/forms/button_toggle_select.html +++ b/artel/store/templates/store/forms/button_toggle_select.html @@ -10,19 +10,3 @@ {% endfor %} {% endwith %} - From d688c00a8028f328de6c70c79eb405986df53248 Mon Sep 17 00:00:00 2001 From: mtyton Date: Thu, 10 Aug 2023 22:52:22 +0200 Subject: [PATCH 3/6] quick fix --- artel/store/loader.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artel/store/loader.py b/artel/store/loader.py index 92f7938..0d2ee1d 100644 --- a/artel/store/loader.py +++ b/artel/store/loader.py @@ -4,6 +4,7 @@ import requests import pandas as pd from django.core.files.base import ContentFile +from django.conf import settings from store.models import ( ProductTemplate, ProductCategoryParamValue, @@ -42,8 +43,9 @@ class ProductLoader(BaseLoader): def _get_images(self, row) -> list[ContentFile]: url = row["images"] images = [] - response = requests.get(url+"/download", stream=True) - print(response.status_code) + response = requests.get( + url+"/preview", stream=True + ) if response.status_code == 200: data = response.content image = ContentFile(data, name=row["template"]) From a7a22e79624f1847cfa1d388eb7370644efede09 Mon Sep 17 00:00:00 2001 From: mtyton Date: Tue, 15 Aug 2023 13:36:11 +0200 Subject: [PATCH 4/6] modifed parrams assignment --- artel/store/admin.py | 6 +- artel/store/forms.py | 4 +- artel/store/loader.py | 20 +++---- artel/store/models.py | 95 ++++++++++++++++---------------- artel/store/tests/factories.py | 34 ++++++------ artel/store/tests/test_loader.py | 6 +- artel/store/tests/test_models.py | 32 +++++------ artel/store/tests/test_views.py | 24 ++++---- 8 files changed, 110 insertions(+), 111 deletions(-) diff --git a/artel/store/admin.py b/artel/store/admin.py index 0a6aa7f..796fbd7 100644 --- a/artel/store/admin.py +++ b/artel/store/admin.py @@ -20,8 +20,8 @@ class ProductCategoryAdmin(ModelAdmin): list_display = ("name", ) -class ProductCategoryParamAdmin(ModelAdmin): - model = models.ProductCategoryParam +class ProductTemplateParamAdmin(ModelAdmin): + model = models.ProductTemplateParam list_display = ("key", "param_type") @@ -59,7 +59,7 @@ class StoreAdminGroup(ModelAdminGroup): items = ( ProductAuthorAdmin, ProductCategoryAdmin, - ProductCategoryParamAdmin, + ProductTemplateParamAdmin, ProductTemplateAdmin, ProductAdmin, DocumentTemplateAdmin, diff --git a/artel/store/forms.py b/artel/store/forms.py index 64ab14f..27cbe40 100644 --- a/artel/store/forms.py +++ b/artel/store/forms.py @@ -5,7 +5,7 @@ from django.db.models import Model from store.models import ( ProductTemplate, - ProductCategoryParamValue, + ProductTemplateParam, Product, PaymentMethod, DeliveryMethod @@ -74,7 +74,7 @@ class ProductTemplateConfigForm(forms.Form): category_params = template.category.category_params.all() for param in category_params: self.fields[param.key] = forms.ModelChoiceField( - queryset=ProductCategoryParamValue.objects.filter(param=param), + queryset=ProductTemplateParam.objects.filter(param=param), widget=ButtonToggleSelect(attrs={"class": "btn-group btn-group-toggle"}), ) diff --git a/artel/store/loader.py b/artel/store/loader.py index 8174711..214e42c 100644 --- a/artel/store/loader.py +++ b/artel/store/loader.py @@ -2,11 +2,11 @@ import logging import requests import pandas as pd -from django.core import files +from django.core.files.base import ContentFile from store.models import ( ProductTemplate, - ProductCategoryParamValue, + ProductTemplateParam, Product, ProductImage ) @@ -29,7 +29,7 @@ class TemplateLoader(BaseLoader): class ProductLoader(BaseLoader): - def _get_images(self, row) -> list[files.ContentFile]: + def _get_images(self, row) -> list[ContentFile]: urls = row["images"] images = [] for url in urls: @@ -37,28 +37,28 @@ class ProductLoader(BaseLoader): if response.status_code == 200: data = response.raw file_name = url.split("/")[-1] - image = files.ContentFile(data, name=file_name) + image = ContentFile(data, name=file_name) images.append(image) return images def _process_row(self, row): template = ProductTemplate.objects.get(code=row["template"]) - price = float(row["price"]) + price = float(row["price"].strip("zł").replace(",", ".")) name = row["name"] available = bool(row["available"]) params = [] for param in row["params"]: key, value = param - param = ProductCategoryParamValue.objects.get(param__key=key, value=value) + param = ProductTemplateParam.objects.get(param__key=key, value=value) params.append(param) product = Product.objects.get_or_create_by_params(template=template, params=params) product.price = price product.name = name product.available = available - - images = self._get_images(row) - for i, image in enumerate(images): - ProductImage.objects.create(product=product, image=image, is_main=bool(i==0)) + # NOTE - temporary solution + # images = self._get_images(row) + # for i, image in enumerate(images): + # ProductImage.objects.create(product=product, image=image, is_main=bool(i==0)) product.save() return product diff --git a/artel/store/models.py b/artel/store/models.py index 2919cf9..8bb104f 100644 --- a/artel/store/models.py +++ b/artel/store/models.py @@ -95,54 +95,12 @@ class ProductCategory(ClusterableModel): ] -class CategoryParamTypeChoices(models.TextChoices): - INT = "int" - STRING = "str" - FLOAT = "float" - - -class ProductCategoryParam(ClusterableModel): - category = ParentalKey(ProductCategory, on_delete=models.CASCADE, related_name="category_params") - key = models.CharField(max_length=200) - param_type = models.CharField(max_length=200, choices=CategoryParamTypeChoices.choices) - - def __str__(self): - return self.key - - panels = [ - FieldPanel("category"), - FieldPanel("key"), - FieldPanel("param_type"), - InlinePanel("param_values") - ] - - def get_available_values(self) -> Iterator[any]: - for elem in self.param_values.all(): - yield elem.get_value() - - -class ProductCategoryParamValue(ClusterableModel): - param = ParentalKey(ProductCategoryParam, on_delete=models.CASCADE, related_name="param_values") - value = models.CharField(max_length=255) - - def get_value(self): - try: - func = getattr(builtins, self.param.param_type) - return func(self.value) - except ValueError: - return - - def __str__(self): - return f"{self.param.key}: {self.value}" - - class ProductTemplate(ClusterableModel): category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE) author = models.ForeignKey(ProductAuthor, on_delete=models.CASCADE) title = models.CharField(max_length=255) code = models.CharField(max_length=255) description = models.TextField(blank=True) - # TODO - add mechanism for enabling params tags = TaggableManager() @@ -175,9 +133,50 @@ class ProductTemplateImage(BaseImageModel): is_main = models.BooleanField(default=False) +class TemplateParamValueChoices(models.TextChoices): + INT = "int" + STRING = "str" + FLOAT = "float" + + +class ProductTemplateParam(ClusterableModel): + template = ParentalKey(ProductTemplate, on_delete=models.CASCADE, related_name="template_params") + key = models.CharField(max_length=200) + param_type = models.CharField(max_length=200, choices=TemplateParamValueChoices.choices) + + def __str__(self): + return self.key + + panels = [ + FieldPanel("category"), + FieldPanel("key"), + FieldPanel("param_type"), + InlinePanel("param_values") + ] + + def get_available_values(self) -> Iterator[any]: + for elem in self.param_values.all(): + yield elem.get_value() + + +class ProductTemplateParamValue(ClusterableModel): + param = ParentalKey(ProductTemplateParam, on_delete=models.CASCADE, related_name="param_values") + value = models.CharField(max_length=255) + + def get_value(self): + try: + func = getattr(builtins, self.param.param_type) + return func(self.value) + except ValueError: + return + + def __str__(self): + return f"{self.param.key}: {self.value}" + + class ProductManager(models.Manager): - def get_or_create_by_params(self, params: list[ProductCategoryParamValue], template: ProductTemplate): + def get_or_create_by_params(self, params: list[ProductTemplateParam], template: ProductTemplate): products = self.filter(template=template) for param in params: @@ -208,8 +207,8 @@ class Product(ClusterableModel): name = models.CharField(max_length=255, blank=True) template = models.ForeignKey(ProductTemplate, on_delete=models.CASCADE, related_name="products") params = models.ManyToManyField( - ProductCategoryParamValue, blank=True, through="ProductParam", - limit_choices_to=models.Q(param__category=models.F("product__template__category")) + ProductTemplateParamValue, blank=True, through="ProductParam", + limit_choices_to=models.Q(param__template=models.F("product__template")) ) price = models.FloatField() available = models.BooleanField(default=True) @@ -260,7 +259,7 @@ class ProductImage(BaseImageModel): class ProductParam(models.Model): product = ParentalKey(Product, on_delete=models.CASCADE, related_name="product_params") - param_value = models.ForeignKey(ProductCategoryParamValue, on_delete=models.CASCADE) + param_value = models.ForeignKey(ProductTemplateParamValue, on_delete=models.CASCADE) def save(self, *args, **kwargs): self.full_clean() @@ -277,8 +276,8 @@ def validate_param(sender, **kwargs): errors = [] for pk in pk_set: try: - param = ProductCategoryParamValue.objects.get(pk=pk).param - except ProductCategoryParamValue.DoesNotExist as e: + param = ProductTemplateParamValue.objects.get(pk=pk).param + except ProductTemplateParamValue.DoesNotExist as e: logger.exception(f"Product param validation failed with exception: {str(e)}") count = product_instance.params.filter(productparam__param_value__param=param).count() if count >= 1: diff --git a/artel/store/tests/factories.py b/artel/store/tests/factories.py index 261da7a..d951619 100644 --- a/artel/store/tests/factories.py +++ b/artel/store/tests/factories.py @@ -31,23 +31,6 @@ class ProductCategoryFactory(DjangoModelFactory): name = Faker('name') -class ProductCategoryParamFactory(DjangoModelFactory): - class Meta: - model = 'store.ProductCategoryParam' - - key = Faker('name') - category = SubFactory(ProductCategoryFactory) - param_type = 'str' - - -class ProductCategoryParamValueFactory(DjangoModelFactory): - class Meta: - model = 'store.ProductCategoryParamValue' - - param = SubFactory(ProductCategoryParamFactory) - value = Faker('name') - - class ProductTemplateFactory(DjangoModelFactory): class Meta: model = 'store.ProductTemplate' @@ -59,6 +42,23 @@ class ProductTemplateFactory(DjangoModelFactory): category = SubFactory(ProductCategoryFactory) +class ProductTemplateParamFactory(DjangoModelFactory): + class Meta: + model = 'store.ProductTemplateParam' + + key = Faker('name') + template = SubFactory(ProductTemplateFactory) + param_type = 'str' + + +class ProductTemplateParamValueFactory(DjangoModelFactory): + class Meta: + model = 'store.ProductTemplateParamValue' + + param = SubFactory(ProductTemplateParamFactory) + value = Faker('name') + + class ProductFactory(DjangoModelFactory): class Meta: model = 'store.Product' diff --git a/artel/store/tests/test_loader.py b/artel/store/tests/test_loader.py index 9ee9c98..428b239 100644 --- a/artel/store/tests/test_loader.py +++ b/artel/store/tests/test_loader.py @@ -10,8 +10,8 @@ class TestProductLoader(TestCase): def setUp(self) -> None: self.category = factories.ProductCategoryFactory() self.template = factories.ProductTemplateFactory(category=self.category) - self.category_params = [factories.ProductCategoryParamFactory(category=self.category) for _ in range(3)] - self.category_param_values = [factories.ProductCategoryParamValueFactory(param=param) for param in self.category_params] + self.category_params = [factories.ProductTemplateParamFactory(category=self.category) for _ in range(3)] + self.category_param_values = [factories.ProductTemplateParamValueFactory(param=param) for param in self.category_params] def test_load_products_single_product_success(self): fake_df = pd.DataFrame({ @@ -93,5 +93,5 @@ class TestProductLoader(TestCase): loader.process() self.assertEqual(self.template.products.count(), 0) - mock_logger.exception.assert_called_with("ProductCategoryParamValue matching query does not exist.") + mock_logger.exception.assert_called_with("ProductTemplateyParamValue matching query does not exist.") \ No newline at end of file diff --git a/artel/store/tests/test_models.py b/artel/store/tests/test_models.py index e3ffe3b..6568242 100644 --- a/artel/store/tests/test_models.py +++ b/artel/store/tests/test_models.py @@ -26,21 +26,21 @@ class ProductCategoryParamTestCase(TestCase): self.assertEqual(available_values, []) def test_get_available_values_one_value_success(self): - factories.ProductCategoryParamValueFactory(param=self.param, value="23") + factories.ProductTemplateParamValueFactory(param=self.param, value="23") available_values = [v for v in self.param.get_available_values()] self.assertEqual(available_values, [23]) self.assertEqual(len(available_values), 1) def test_get_available_values_multiple_values_success(self): - factories.ProductCategoryParamValueFactory(param=self.param, value="23") - factories.ProductCategoryParamValueFactory(param=self.param, value="24") - factories.ProductCategoryParamValueFactory(param=self.param, value="25") + factories.ProductTemplateParamValueFactory(param=self.param, value="23") + factories.ProductTemplateParamValueFactory(param=self.param, value="24") + factories.ProductTemplateParamValueFactory(param=self.param, value="25") available_values = [v for v in self.param.get_available_values()] self.assertEqual(available_values, [23, 24, 25]) self.assertEqual(len(available_values), 3) -class ProductCategoryParamValueTestCase(TestCase): +class ProductTemplateParamValueTestCase(TestCase): def setUp(self): super().setUp() self.category = factories.ProductCategoryFactory() @@ -52,7 +52,7 @@ class ProductCategoryParamValueTestCase(TestCase): param_type="int", key="test_param" ) - param_value = factories.ProductCategoryParamValueFactory(param=param, value="23") + param_value = factories.ProductTemplateParamValueFactory(param=param, value="23") proper_value = param_value.get_value() self.assertEqual(proper_value, 23) @@ -62,7 +62,7 @@ class ProductCategoryParamValueTestCase(TestCase): param_type="int", key="test_param" ) - param_value = factories.ProductCategoryParamValueFactory(param=param, value="wrong_value") + param_value = factories.ProductTemplateParamValueFactory(param=param, value="wrong_value") proper_value = param_value.get_value() self.assertEqual(proper_value, None) @@ -76,7 +76,7 @@ class ProductTestCase(TestCase): param_type="int", key="test_param" ) - param_value = factories.ProductCategoryParamValueFactory(param=param, value="23") + param_value = factories.ProductTemplateParamValueFactory(param=param, value="23") with transaction.atomic(): product.params.add(param_value) product.save() @@ -90,8 +90,8 @@ class ProductTestCase(TestCase): param_type="int", key="test_param" ) - param_value = factories.ProductCategoryParamValueFactory(param=param, value="23") - sec_param_value = factories.ProductCategoryParamValueFactory(param=param, value="24") + param_value = factories.ProductTemplateParamValueFactory(param=param, value="23") + sec_param_value = factories.ProductTemplateParamValueFactory(param=param, value="24") with self.assertRaises(ValidationError): with transaction.atomic(): product.params.add(param_value) @@ -100,8 +100,8 @@ class ProductTestCase(TestCase): def test_get_or_create_by_params_success(self): product = factories.ProductFactory(available=True) - value1 = factories.ProductCategoryParamValueFactory() - value2 = factories.ProductCategoryParamValueFactory() + value1 = factories.ProductTemplateParamValueFactory() + value2 = factories.ProductTemplateParamValueFactory() product.params.add(value1) product.params.add(value2) product.save() @@ -114,8 +114,8 @@ class ProductTestCase(TestCase): def test_get_or_create_by_params_success_not_existing_product(self): product = factories.ProductFactory(available=True) - value1 = factories.ProductCategoryParamValueFactory() - value2 = factories.ProductCategoryParamValueFactory() + value1 = factories.ProductTemplateParamValueFactory() + value2 = factories.ProductTemplateParamValueFactory() product.params.add(value1) product.price = 13.0 product.save() @@ -130,8 +130,8 @@ class ProductTestCase(TestCase): def test_get_or_create_by_params_success_not_existing_product_no_other_products(self): template = factories.ProductTemplateFactory() - value1 = factories.ProductCategoryParamValueFactory() - value2 = factories.ProductCategoryParamValueFactory() + value1 = factories.ProductTemplateParamValueFactory() + value2 = factories.ProductTemplateParamValueFactory() prod = store_models.Product.objects.get_or_create_by_params( params=[value1, value2], template=template, diff --git a/artel/store/tests/test_views.py b/artel/store/tests/test_views.py index ca6acb1..5883fb7 100644 --- a/artel/store/tests/test_views.py +++ b/artel/store/tests/test_views.py @@ -2,15 +2,15 @@ from django.test import TestCase from django.shortcuts import reverse from store.models import ( - ProductCategoryParam, - ProductCategoryParamValue, - CategoryParamTypeChoices + ProductTemplateParam, + ProductTemplateParamValue, + TemplateParamValueChoices ) from store.tests.factories import ( ProductTemplateFactory, ProductCategoryFactory, ProductFactory, - ProductCategoryParamValueFactory + ProductTemplateParamValueFactory ) @@ -21,18 +21,18 @@ class ConfigureProductViewTestCase(TestCase): self.category = ProductCategoryFactory() self.product_template = ProductTemplateFactory(category=self.category) # create template params and values for those params - self.param1 = ProductCategoryParam.objects.create( + self.param1 = ProductTemplateParam.objects.create( key="Mocowanie", category=self.category, - param_type=CategoryParamTypeChoices.STRING + param_type=TemplateParamValueChoices.STRING ) - self.param1_value1 = ProductCategoryParamValueFactory(param=self.param1) - self.param1_value2 = ProductCategoryParamValueFactory(param=self.param1) - self.param2 = ProductCategoryParam.objects.create( + self.param1_value1 = ProductTemplateParamValueFactory(param=self.param1) + self.param1_value2 = ProductTemplateParamValueFactory(param=self.param1) + self.param2 = ProductTemplateParam.objects.create( key="Format", category=self.category, - param_type=CategoryParamTypeChoices.STRING + param_type=TemplateParamValueChoices.STRING ) - self.param2_value1 = ProductCategoryParamValueFactory(param=self.param2) - self.param2_value2 = ProductCategoryParamValueFactory(param=self.param2) + self.param2_value1 = ProductTemplateParamValueFactory(param=self.param2) + self.param2_value2 = ProductTemplateParamValueFactory(param=self.param2) # create product variant self.variant1 = ProductFactory( template=self.product_template From 2a00adb981a3cf6c5af625ba1a9ca85bad9eb3af Mon Sep 17 00:00:00 2001 From: mtyton Date: Tue, 15 Aug 2023 21:03:14 +0200 Subject: [PATCH 5/6] added missing migration --- ...lateparam_alter_product_params_and_more.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 artel/store/migrations/0013_producttemplateparam_alter_product_params_and_more.py diff --git a/artel/store/migrations/0013_producttemplateparam_alter_product_params_and_more.py b/artel/store/migrations/0013_producttemplateparam_alter_product_params_and_more.py new file mode 100644 index 0000000..add7879 --- /dev/null +++ b/artel/store/migrations/0013_producttemplateparam_alter_product_params_and_more.py @@ -0,0 +1,62 @@ +# Generated by Django 4.1.10 on 2023-08-15 10:44 + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + dependencies = [ + ("store", "0012_deliverymethod_order_uuid_product_uuid_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="ProductTemplateParam", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("key", models.CharField(max_length=200)), + ( + "param_type", + models.CharField(choices=[("int", "Int"), ("str", "String"), ("float", "Float")], max_length=200), + ), + ( + "template", + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="template_params", + to="store.producttemplate", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.AlterField( + model_name="product", + name="params", + field=models.ManyToManyField( + blank=True, + limit_choices_to=models.Q(("param__template", models.F("product__template"))), + through="store.ProductParam", + to="store.productcategoryparamvalue", + ), + ), + migrations.RenameModel( + old_name="ProductCategoryParamValue", + new_name="ProductTemplateParamValue", + ), + migrations.DeleteModel( + name="ProductCategoryParam", + ), + migrations.AlterField( + model_name="producttemplateparamvalue", + name="param", + field=modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="param_values", + to="store.producttemplateparam", + ), + ), + ] From 6c813dc94b71cf8b91283d40c03f759e49f9dcb0 Mon Sep 17 00:00:00 2001 From: mtyton Date: Tue, 15 Aug 2023 21:16:43 +0200 Subject: [PATCH 6/6] fixed admin view --- artel/store/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artel/store/models.py b/artel/store/models.py index f7f20bd..5e32d13 100644 --- a/artel/store/models.py +++ b/artel/store/models.py @@ -148,7 +148,7 @@ class ProductTemplateParam(ClusterableModel): return self.key panels = [ - FieldPanel("category"), + FieldPanel("template"), FieldPanel("key"), FieldPanel("param_type"), InlinePanel("param_values")