sforkowany z mtyton/comfy
modifed parrams assignment
rodzic
7c8ed587e3
commit
a7a22e7962
|
@ -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,
|
||||
|
|
|
@ -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"}),
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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.")
|
||||
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue