From 70614abc03baf860c24a1f7aec40f185a94ee9e8 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Tue, 12 Nov 2019 17:39:57 +0300 Subject: [PATCH] - renamed fix_wine_color_tag to fix_wine_color_tag - added command add_assemblage_tag - added transfer commands: cepage, assemblage (execute in this order) --- .../management/commands/add_assemblage_tag.py | 21 ++++++ ...r_content_tag.py => fix_wine_color_tag.py} | 6 +- apps/tag/models.py | 2 + apps/tag/transfer_data.py | 37 ++++++++++ apps/transfer/management/commands/transfer.py | 2 + apps/transfer/mixins.py | 8 ++- apps/transfer/models.py | 24 +++++++ apps/transfer/serializers/product.py | 67 +++++++++++++++---- apps/transfer/serializers/tag.py | 61 +++++++++++++++++ 9 files changed, 211 insertions(+), 17 deletions(-) create mode 100644 apps/product/management/commands/add_assemblage_tag.py rename apps/product/management/commands/{fix_sugar_content_tag.py => fix_wine_color_tag.py} (80%) create mode 100644 apps/tag/transfer_data.py create mode 100644 apps/transfer/serializers/tag.py diff --git a/apps/product/management/commands/add_assemblage_tag.py b/apps/product/management/commands/add_assemblage_tag.py new file mode 100644 index 00000000..faf07c39 --- /dev/null +++ b/apps/product/management/commands/add_assemblage_tag.py @@ -0,0 +1,21 @@ +from django.core.management.base import BaseCommand + +from transfer.models import Assemblages +from transfer.serializers.product import AssemblageTagSerializer + + +class Command(BaseCommand): + help = 'Add assemblage tag to product' + + def handle(self, *args, **kwarg): + errors = [] + legacy_products = Assemblages.objects.filter(product_id__isnull=False) + serialized_data = AssemblageTagSerializer( + data=list(legacy_products.values()), + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + for d in serialized_data.errors: errors.append(d) if d else None + + self.stdout.write(self.style.WARNING(f'Error count: {len(errors)}\nErrors: {errors}')) diff --git a/apps/product/management/commands/fix_sugar_content_tag.py b/apps/product/management/commands/fix_wine_color_tag.py similarity index 80% rename from apps/product/management/commands/fix_sugar_content_tag.py rename to apps/product/management/commands/fix_wine_color_tag.py index 22a08807..f4d4d6fe 100644 --- a/apps/product/management/commands/fix_sugar_content_tag.py +++ b/apps/product/management/commands/fix_wine_color_tag.py @@ -1,16 +1,16 @@ from django.core.management.base import BaseCommand from transfer import models as transfer_models -from transfer.serializers.product import ProductTagSerializer +from transfer.serializers.product import WineColorTagSerializer class Command(BaseCommand): - help = 'Fix sugar content tag' + help = 'Fix wine color tag' def handle(self, *args, **kwarg): errors = [] legacy_products = transfer_models.Products.objects.filter(wine_color__isnull=False) - serialized_data = ProductTagSerializer( + serialized_data = WineColorTagSerializer( data=list(legacy_products.values()), many=True) if serialized_data.is_valid(): diff --git a/apps/tag/models.py b/apps/tag/models.py index 5965b4fb..45200290 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -107,11 +107,13 @@ class TagCategory(TranslatedFieldsMixin, models.Model): STRING = 'string' LIST = 'list' INTEGER = 'integer' + PERCENTAGE = 'percentage' VALUE_TYPE_CHOICES = ( (STRING, _('string')), (LIST, _('list')), (INTEGER, _('integer')), + (PERCENTAGE, _('percentage')), ) label = TJSONField(blank=True, null=True, default=None, diff --git a/apps/tag/transfer_data.py b/apps/tag/transfer_data.py new file mode 100644 index 00000000..b94fd0a0 --- /dev/null +++ b/apps/tag/transfer_data.py @@ -0,0 +1,37 @@ +from pprint import pprint + +from transfer import models as transfer_models +from transfer.serializers.tag import AssemblageTagSerializer, \ + CepagesTagCategorySerializer + + +def transfer_assemblage(): + queryset = transfer_models.Assemblages.objects.all() + serialized_data = AssemblageTagSerializer( + data=list(queryset.values()), + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + pprint(f"transfer_wine_color errors: {serialized_data.errors}") + + +def transfer_cepages(): + queryset = transfer_models.Cepages.objects.all() + serialized_data = CepagesTagCategorySerializer( + data=list(queryset.values()), + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + pprint(f"transfer_cepages errors: {serialized_data.errors}") + + +data_types = { + "cepage": [ + transfer_cepages + ], + "assemblage": [ + transfer_assemblage, + ] +} diff --git a/apps/transfer/management/commands/transfer.py b/apps/transfer/management/commands/transfer.py index 7f0b5f4b..9159a20c 100644 --- a/apps/transfer/management/commands/transfer.py +++ b/apps/transfer/management/commands/transfer.py @@ -35,6 +35,8 @@ class Command(BaseCommand): 'product_note', 'souvenir', 'establishment_note', + 'cepage', + 'assemblage', ] def handle(self, *args, **options): diff --git a/apps/transfer/mixins.py b/apps/transfer/mixins.py index 7b69bbb4..31d2bc2d 100644 --- a/apps/transfer/mixins.py +++ b/apps/transfer/mixins.py @@ -3,7 +3,7 @@ from django.forms.models import model_to_dict from rest_framework import serializers from tag import models as tag_models from django.conf import settings -from product.models import ProductType, ProductSubType +from product.models import ProductType, ProductSubType, Product from django.utils.text import slugify @@ -103,3 +103,9 @@ class TransferSerializerMixin(serializers.ModelSerializer): category__index_name=category_index_name) if qs.exists(): return qs.first() + + def get_product(self, old_id): + if old_id: + product_qs = Product.objects.filter(old_id=old_id) + if product_qs.exists(): + return product_qs.first() diff --git a/apps/transfer/models.py b/apps/transfer/models.py index 2c7fe726..079e788a 100644 --- a/apps/transfer/models.py +++ b/apps/transfer/models.py @@ -1153,3 +1153,27 @@ class GridItems(MigrateMixin): class Meta: managed = False db_table = 'grid_items' + + +class Assemblages(MigrateMixin): + + using = 'legacy' + + percent = models.FloatField() + cepage = models.ForeignKey('Cepages', on_delete=models.DO_NOTHING) + product_id = models.IntegerField() + + class Meta: + managed = False + db_table = 'assemblages' + + +class Cepages(MigrateMixin): + + using = 'legacy' + + name = models.CharField(max_length=255) + + class Meta: + managed = False + db_table = 'cepages' diff --git a/apps/transfer/serializers/product.py b/apps/transfer/serializers/product.py index 75508677..dc5b088f 100644 --- a/apps/transfer/serializers/product.py +++ b/apps/transfer/serializers/product.py @@ -352,11 +352,11 @@ class ProductSerializer(TransferSerializerMixin): obj = qs.first() # adding classification - obj.classifications.add(*[i for i in classifications if i]) + obj.classifications.add(*[i for i in classifications if i and i not in obj.classifications.all()]) # adding standard - obj.standards.add(*[i for i in standards if i]) + obj.standards.add(*[i for i in standards if i and i not in obj.standards.all()]) # adding tags - obj.tags.add(*[i for i in tags if i]) + obj.tags.add(*[i for i in tags if i and i not in obj.tags.all()]) return obj def get_name(self, name, brand): @@ -423,7 +423,7 @@ class ProductSerializer(TransferSerializerMixin): return False -class ProductTagSerializer(TransferSerializerMixin): +class WineColorTagSerializer(TransferSerializerMixin): """Serializer for fixing existing products with missing tags.""" id = serializers.IntegerField() @@ -454,7 +454,8 @@ class ProductTagSerializer(TransferSerializerMixin): obj = qs.first() # adding missing tag - obj.tags.add(wine_color_tag) + if wine_color_tag in obj.tags.all(): + obj.tags.add(wine_color_tag) return obj @@ -503,7 +504,7 @@ class PlateSerializer(TransferSerializerMixin): return obj -class PlateImageSerializer(serializers.ModelSerializer): +class PlateImageSerializer(TransferSerializerMixin): id = serializers.IntegerField() name = serializers.CharField() @@ -536,14 +537,8 @@ class PlateImageSerializer(serializers.ModelSerializer): image=image_url) return obj if created else None - def get_product(self, product_id): - if product_id: - product_qs = models.Product.objects.filter(old_id=product_id) - if product_qs.exists(): - return product_qs.first() - -class ProductNoteSerializer(serializers.ModelSerializer): +class ProductNoteSerializer(TransferSerializerMixin): id = serializers.IntegerField() product_id = serializers.IntegerField() @@ -574,3 +569,49 @@ class ProductNoteSerializer(serializers.ModelSerializer): qs = models.Product.objects.filter(old_id=old_id) if qs.exists(): return qs.first() + + +class AssemblageTagSerializer(TransferSerializerMixin): + + percent = serializers.FloatField() + cepage_id = serializers.PrimaryKeyRelatedField( + queryset=transfer_models.Cepages.objects.all()) + product_id = serializers.IntegerField() + + class Meta(ProductSerializer.Meta): + fields = ( + 'percent', + 'cepage_id', # tag category + 'product_id', + ) + + def validate(self, attrs): + tag_category = attrs.pop('cepage_id') + tag = str(attrs.pop('percent')) + + attrs['product'] = self.get_product(attrs.pop('product_id')) + attrs['tag'] = self.get_tag(tag, self.get_tag_category(tag_category)) + return attrs + + def create(self, validated_data): + obj = validated_data.pop('product', None) + tag = validated_data.pop('tag', None) + + if obj and tag: + if tag not in obj.tags.all(): + obj.tags.add(tag) + return obj + + def get_tag(self, tag, tag_category): + if tag and tag_category: + qs = tag_models.Tag.objects.filter(category=tag_category, + value=tag) + if qs.exists(): + return qs.first() + + def get_tag_category(self, tag_category): + if isinstance(tag_category, transfer_models.Cepages): + tag_category = tag_category.name + qs = tag_models.TagCategory.objects.filter(index_name=slugify(tag_category)) + if qs.exists(): + return qs.first() diff --git a/apps/transfer/serializers/tag.py b/apps/transfer/serializers/tag.py new file mode 100644 index 00000000..db4a882c --- /dev/null +++ b/apps/transfer/serializers/tag.py @@ -0,0 +1,61 @@ +from transfer.mixins import TransferSerializerMixin +from django.utils.text import slugify +from rest_framework import serializers +from tag.models import Tag, TagCategory +from transfer.models import Cepages +from django.conf import settings + + +class AssemblageTagSerializer(TransferSerializerMixin): + + percent = serializers.FloatField() + cepage_id = serializers.PrimaryKeyRelatedField( + queryset=Cepages.objects.all()) + + class Meta: + model = Tag + fields = ( + 'percent', + 'cepage_id', + ) + + def validate(self, attrs): + name = attrs.pop('percent') + cepage = attrs.pop('cepage_id') + + attrs['label'] = {settings.FALLBACK_LOCALE: name} + attrs['value'] = name + attrs['category'] = self.get_tag_category(cepage) + return attrs + + def create(self, validated_data): + qs = self.Meta.model.objects.filter(**validated_data) + category = validated_data.get('category') + if not qs.exists() and category: + return super().create(validated_data) + + def get_tag_category(self, cepage): + cepage_name = cepage.name if isinstance(cepage, Cepages) else cepage + qs = TagCategory.objects.filter(index_name=slugify(cepage_name)) + if qs.exists(): + return qs.first() + + +class CepagesTagCategorySerializer(TransferSerializerMixin): + + name = serializers.CharField() + + class Meta: + model = TagCategory + fields = ( + 'name', + ) + + def validate(self, attrs): + name = attrs.pop('name') + + attrs['label'] = {settings.FALLBACK_LOCALE: name} + attrs['public'] = True + attrs['index_name'] = slugify(name) + attrs['value_type'] = TagCategory.PERCENTAGE + return attrs