From 0f2d1ca071d496e4242034b5883e41f19cabb89c Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 8 Nov 2019 19:46:16 +0300 Subject: [PATCH] need checks --- apps/product/models.py | 124 +++++----- apps/product/transfer_data.py | 113 +++++++--- apps/transfer/mixins.py | 16 ++ apps/transfer/models.py | 9 +- apps/transfer/serializers/product.py | 325 ++++++++++++++++++++------- 5 files changed, 428 insertions(+), 159 deletions(-) diff --git a/apps/product/models.py b/apps/product/models.py index 954f0693..a894e9a0 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -4,6 +4,7 @@ from django.contrib.gis.db import models as gis_models from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ +from django.core.validators import MaxValueValidator, MinValueValidator from utils.models import (BaseAttributes, ProjectBaseMixin, TranslatedFieldsMixin, TJSONField) @@ -18,11 +19,15 @@ class ProductType(TranslatedFieldsMixin, ProjectBaseMixin): FOOD = 'food' WINE = 'wine' LIQUOR = 'liquor' + SOUVENIR = 'souvenir' + BOOK = 'book' INDEX_NAME_TYPES = ( (FOOD, _('Food')), (WINE, _('Wine')), (LIQUOR, _('Liquor')), + (SOUVENIR, _('Souvenir')), + (BOOK, _('Book')), ) name = TJSONField(blank=True, null=True, default=None, @@ -49,29 +54,13 @@ class ProductSubType(TranslatedFieldsMixin, ProjectBaseMixin): # INDEX NAME CHOICES RUM = 'rum' + PLATE = 'plate' OTHER = 'other' - EXTRA_BRUT = 'extra brut' - BRUT = 'brut' - BRUT_NATURE = 'brut nature' - DEMI_SEC = 'demi-sec' - EXTRA_DRY = 'Extra Dry' - DOSAGE_ZERO = 'dosage zero' - SEC = 'sec' - DOUX = 'doux' - MOELLEUX= 'moelleux' INDEX_NAME_TYPES = ( (RUM, _('Rum')), + (PLATE, _('Plate')), (OTHER, _('Other')), - (EXTRA_BRUT, _('extra brut')), - (BRUT, _('brut')), - (BRUT_NATURE, _('brut nature')), - (DEMI_SEC, _('demi-sec')), - (EXTRA_DRY, _('Extra Dry')), - (DOSAGE_ZERO, _('dosage zero')), - (SEC, _('sec')), - (DOUX, _('doux')), - (MOELLEUX, _('moelleux')) ) product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE, @@ -188,11 +177,15 @@ class Product(TranslatedFieldsMixin, BaseAttributes): verbose_name=_('public mark'),) wine_region = models.ForeignKey('location.WineRegion', on_delete=models.PROTECT, related_name='wines', - blank=True, null=True, + blank=True, null=True, default=None, verbose_name=_('wine region')) - wine_standard = models.ForeignKey('product.WineStandard', on_delete=models.PROTECT, - blank=True, null=True, - verbose_name=_('wine standard')) + wine_sub_region = models.ForeignKey('location.WineSubRegion', on_delete=models.PROTECT, + related_name='wines', + blank=True, null=True, default=None, + verbose_name=_('wine sub region')) + classifications = models.ManyToManyField('product.ProductClassification', + blank=True, + verbose_name=_('classifications')) wine_village = models.ForeignKey('location.WineVillage', on_delete=models.PROTECT, blank=True, null=True, verbose_name=_('wine appellation')) @@ -209,6 +202,13 @@ class Product(TranslatedFieldsMixin, BaseAttributes): verbose_name=_('brand')) tags = models.ManyToManyField('tag.Tag', related_name='products', verbose_name=_('Tag')) + old_unique_key = models.CharField(max_length=255, unique=True, + blank=True, null=True, default=None, + help_text=_('attribute from legacy db')) + vintage = models.IntegerField(verbose_name=_('vintage year'), + null=True, blank=True, default=None, + validators=[MinValueValidator(1900), + MaxValueValidator(2100)]) objects = ProductManager.from_queryset(ProductQuerySet)() @@ -271,33 +271,31 @@ class Unit(models.Model): return self.name -class WineStandardQuerySet(models.QuerySet): - """Wine appellation queryset.""" +class ProductStandardQuerySet(models.QuerySet): + """Product standard queryset.""" -class WineStandard(models.Model): - """Wine standard model.""" +class ProductStandard(models.Model): + """Product standard model.""" - APPELLATION = 'Appellation' - CLASSIFICATION = 'Classification' - WINEQUALITY = 'WineQuality' - YARDCLASSIFICATION = 'YardClassification' + APPELLATION = 0 + WINEQUALITY = 1 + YARDCLASSIFICATION = 2 STANDARDS = ( (APPELLATION, _('Appellation')), - (CLASSIFICATION, _('Classification')), (WINEQUALITY, _('Wine quality')), (YARDCLASSIFICATION, _('Yard classification')), ) name = models.CharField(_('name'), max_length=255) - standard_type = models.CharField(max_length=30, choices=STANDARDS, - verbose_name=_('standard type')) + standard_type = models.PositiveSmallIntegerField(choices=STANDARDS, + verbose_name=_('standard type')) coordinates = gis_models.PointField( _('Coordinates'), blank=True, null=True, default=None) old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) - objects = WineStandardQuerySet.as_manager() + objects = ProductStandardQuerySet.as_manager() class Meta: """Meta class.""" @@ -305,25 +303,49 @@ class WineStandard(models.Model): verbose_name = _('wine standard') -class WineClassificationQuerySet(models.QuerySet): - """Wine classification QuerySet.""" +class ProductClassificationType(models.Model): + """Product classification type.""" - -class WineClassification(models.Model): - """Wine classification model.""" - name = models.CharField(_('name'), max_length=255) - standard = models.ForeignKey(WineStandard, on_delete=models.PROTECT, - verbose_name=_('standard')) - tags = models.ManyToManyField('tag.Tag', related_name='wine_classifications', - verbose_name=_('Tag')) - possible_subtype = models.ForeignKey(ProductSubType, on_delete=models.PROTECT, + name = models.CharField(max_length=255, unique=True, + verbose_name=_('classification type')) + product_type = models.ForeignKey(ProductType, on_delete=models.PROTECT, + null=True, default=None, + verbose_name=_('product type')) + product_sub_type = models.ForeignKey(ProductSubType, on_delete=models.PROTECT, blank=True, null=True, default=None, - help_text=_('Legacy attribute - possible_type')) - old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) - - objects = WineClassificationQuerySet.as_manager() + verbose_name=_('product subtype'), + help_text=_('Legacy attribute - possible_type (product type).' + 'Product type in our case is product subtype.')) class Meta: """Meta class.""" - verbose_name = _('wine classification') - verbose_name_plural = _('wine classifications') + verbose_name = _('wine classification type') + verbose_name_plural = _('wine classification types') + + def __str__(self): + """Override str dunder.""" + return self.name + + +class ProductClassificationQuerySet(models.QuerySet): + """Product classification QuerySet.""" + + +class ProductClassification(models.Model): + """Product classification model.""" + + classification_type = models.ForeignKey(ProductClassificationType, on_delete=models.PROTECT, + verbose_name=_('classification type')) + standard = models.ForeignKey(ProductStandard, on_delete=models.PROTECT, + null=True, blank=True, default=None, + verbose_name=_('standard')) + tags = models.ManyToManyField('tag.Tag', related_name='product_classifications', + verbose_name=_('Tag')) + old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) + + objects = ProductClassificationQuerySet.as_manager() + + class Meta: + """Meta class.""" + verbose_name = _('product classification') + verbose_name_plural = _('product classifications') diff --git a/apps/product/transfer_data.py b/apps/product/transfer_data.py index 98c4d83c..b1b32eee 100644 --- a/apps/product/transfer_data.py +++ b/apps/product/transfer_data.py @@ -1,10 +1,47 @@ from pprint import pprint from django.conf import settings -from tag.models import TagCategory from transfer import models as transfer_models -from transfer.serializers.partner import PartnerSerializer from transfer.serializers import product as product_serializers +from transfer.serializers.partner import PartnerSerializer + +from product.models import ProductType, ProductSubType + + +def transfer_product_types(): + product_types = ['wine', 'souvenir'] + for product_type in product_types: + ProductType.objects.get_or_create(**{ + 'name': {settings.FALLBACK_LOCALE: product_type}, + 'index_name': product_type + }) + + +def transfer_product_subtype(): + error_counter = 0 + create_counter = 0 + + product_subtypes = { + 'plate': { + 'product_type_index_name': 'souvenir', + 'name': 'plate', + 'index_name': 'plate', + } + } + for product_subtype in product_subtypes.values(): + product_type_qs = ProductType.objects.filter( + index_name=product_subtype.get('product_type_index_name')) + if product_type_qs: + product_type = product_type_qs.first() + subtype, status = ProductSubType.objects.get_or_create(**{ + 'name': {settings.FALLBACK_LOCALE: product_subtype.get('name')}, + 'index_name': product_subtype.get('index_name'), + 'product_type': product_type + }) + create_counter += 1 if status else 0 + else: + error_counter += 1 + print(f'Errors occurred: {error_counter}\nCreated: {create_counter}') def transfer_partner(): @@ -18,16 +55,6 @@ def transfer_partner(): def transfer_wine_color(): - wine_color_index_name = 'wine_color' - - TagCategory.objects.get_or_create( - index_name=wine_color_index_name, - defaults={ - 'label': {settings.FALLBACK_LOCALE: wine_color_index_name}, - 'value_type': TagCategory.STRING, - 'index_name': wine_color_index_name, - 'public': True - }) queryset = transfer_models.WineColor.objects.all() serialized_data = product_serializers.WineColorSerializer( data=list(queryset.values()), @@ -35,20 +62,21 @@ def transfer_wine_color(): if serialized_data.is_valid(): serialized_data.save() else: - pprint(f"WineColorSerializer errors: {serialized_data.errors}") + pprint(f"transfer_wine_color errors: {serialized_data.errors}") + + +def transfer_wine_sugar_content(): + queryset = transfer_models.WineType.objects.all() + serialized_data = product_serializers.WineTypeSerializer( + data=list(queryset.values()), + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + pprint(f"transfer_wine_sugar_content errors: {serialized_data.errors}") def transfer_wine_bottles_produced(): - bottles_produced_index_name = 'bottles_produced' - - TagCategory.objects.get_or_create( - index_name=bottles_produced_index_name, - defaults={ - 'label': {settings.FALLBACK_LOCALE: bottles_produced_index_name}, - 'value_type': TagCategory.STRING, - 'index_name': bottles_produced_index_name, - 'public': True - }) raw_queryset = transfer_models.Products.objects.raw( """ SELECT @@ -60,7 +88,7 @@ def transfer_wine_bottles_produced(): """ ) queryset = [vars(query) for query in raw_queryset] - serialized_data = product_serializers.BottlesProducedSerializer( + serialized_data = product_serializers.WineBottlesProducedSerializer( data=queryset, many=True) if serialized_data.is_valid(): @@ -69,9 +97,29 @@ def transfer_wine_bottles_produced(): pprint(f"transfer_wine_bottles_produced errors: {serialized_data.errors}") +def transfer_wine_classification_type(): + raw_queryset = transfer_models.ProductClassification.objects.raw( + """ + SELECT + DISTINCT name, + 1 as id + FROM wine_classifications; + """ + ) + queryset = [vars(query) for query in raw_queryset] + serialized_data = product_serializers.WineClassificationTypeSerializer( + data=queryset, + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + pprint(f"transfer_classification errors: {serialized_data.errors}") + + def transfer_wine_standard(): - queryset = transfer_models.WineClassification.objects.filter(parent_id__isnull=True) - serialized_data = product_serializers.WineStandardSerializer( + queryset = transfer_models.ProductClassification.objects.filter(parent_id__isnull=True) \ + .exclude(type='Classification') + serialized_data = product_serializers.ProductStandardSerializer( data=list(queryset.values()), many=True) if serialized_data.is_valid(): @@ -81,8 +129,8 @@ def transfer_wine_standard(): def transfer_wine_classifications(): - queryset = transfer_models.WineClassification.objects.filter(parent_id__isnull=False) - serialized_data = product_serializers.WineStandardClassificationSerializer( + queryset = transfer_models.ProductClassification.objects.filter(type='Classification') + serialized_data = product_serializers.ProductClassificationSerializer( data=list(queryset.values()), many=True) if serialized_data.is_valid(): @@ -125,11 +173,18 @@ def transfer_product(): data_types = { "partner": [transfer_partner], + "product_type": [ + transfer_product_types, + transfer_product_subtype, + ], "wine_characteristics": [ + transfer_wine_sugar_content, transfer_wine_color, transfer_wine_bottles_produced, + transfer_wine_classification_type, transfer_wine_standard, - transfer_wine_classifications], + transfer_wine_classifications, + ], "product": [ transfer_product_brand, transfer_product diff --git a/apps/transfer/mixins.py b/apps/transfer/mixins.py index 46ed0477..4ef4d74d 100644 --- a/apps/transfer/mixins.py +++ b/apps/transfer/mixins.py @@ -1,6 +1,9 @@ from django.db import models 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 class SecondDbManager(models.Manager): @@ -34,3 +37,16 @@ class TransferSerializerMixin(serializers.ModelSerializer): qs = self.Meta.model.objects.filter(**validated_data) if not qs.exists(): return super().create(validated_data) + + @property + def tag_category(self): + if self.CATEGORY_LABEL and self.CATEGORY_INDEX_NAME: + tag_category, _ = tag_models.TagCategory.objects.get_or_create( + index_name=self.CATEGORY_INDEX_NAME, + defaults={ + 'label': {settings.FALLBACK_LOCALE: self.CATEGORY_LABEL}, + 'value_type': tag_models.TagCategory.STRING, + 'index_name': self.CATEGORY_INDEX_NAME, + 'public': True + }) + return tag_category diff --git a/apps/transfer/models.py b/apps/transfer/models.py index e4a31dad..9c87970d 100644 --- a/apps/transfer/models.py +++ b/apps/transfer/models.py @@ -919,7 +919,7 @@ class WineType(MigrateMixin): db_table = 'wine_types' -class WineClassification(MigrateMixin): +class ProductClassification(MigrateMixin): using = 'legacy' name = models.CharField(max_length=255) @@ -948,20 +948,21 @@ class Products(MigrateMixin): price = models.FloatField(null=True) average_price_in_shops = models.FloatField(null=True) wine_sub_region_id = models.IntegerField(null=True) - classification = models.ForeignKey('WineClassification', models.DO_NOTHING, null=True, + classification = models.ForeignKey('ProductClassification', models.DO_NOTHING, null=True, related_name='product_classification') wine_region = models.ForeignKey('WineLocations', models.DO_NOTHING, null=True) wine_type = models.ForeignKey('WineType', models.DO_NOTHING, null=True) wine_color = models.ForeignKey('WineColor', models.DO_NOTHING, null=True) - appellation = models.ForeignKey('WineClassification', models.DO_NOTHING, null=True) + appellation = models.ForeignKey('ProductClassification', models.DO_NOTHING, null=True) state = models.CharField(max_length=255) village = models.ForeignKey('WineLocations', models.DO_NOTHING, null=True, related_name='product_village') vineyard = models.ForeignKey('WineLocations', models.DO_NOTHING, null=True, related_name='product_vineyard') - wine_quality = models.ForeignKey('WineClassification', models.DO_NOTHING, null=True, + wine_quality = models.ForeignKey('ProductClassification', models.DO_NOTHING, null=True, related_name='product_wine_quality') bottles_produced = models.CharField(max_length=3000, null=True) + unique_key = models.CharField(max_length=255, null=True) class Meta: managed = False diff --git a/apps/transfer/serializers/product.py b/apps/transfer/serializers/product.py index 880e3906..eb7cb573 100644 --- a/apps/transfer/serializers/product.py +++ b/apps/transfer/serializers/product.py @@ -9,10 +9,12 @@ from transfer import models as transfer_models from utils.methods import get_point_from_coordinates from transfer.mixins import TransferSerializerMixin from django.conf import settings +from functools import reduce class WineColorSerializer(TransferSerializerMixin): - TAG_CATEGORY = 'wine_color' + CATEGORY_LABEL = 'Wine color' + CATEGORY_INDEX_NAME = slugify(CATEGORY_LABEL) id = serializers.IntegerField() name = serializers.CharField(allow_null=True) @@ -35,17 +37,35 @@ class WineColorSerializer(TransferSerializerMixin): attrs['category'] = self.tag_category return attrs - @property - def tag_category(self): - qs = tag_models.TagCategory.objects.filter(index_name=self.TAG_CATEGORY) - if qs.exists(): - return qs.first() + +class WineTypeSerializer(TransferSerializerMixin): + CATEGORY_LABEL = 'Sugar content' + CATEGORY_INDEX_NAME = slugify(CATEGORY_LABEL) + + id = serializers.IntegerField() + name = serializers.CharField() + + class Meta: + model = tag_models.Tag + fields = ( + 'id', + 'name', + ) + + def validate(self, attrs): + value = attrs.pop('name') + attrs['old_id'] = attrs.pop('id', None) + attrs['label'] = {settings.FALLBACK_LOCALE: value} + attrs['value'] = slugify(value) + attrs['category'] = self.tag_category + return attrs -class BottlesProducedSerializer(TransferSerializerMixin): - TAG_CATEGORY = 'bottles_produced' +class WineBottlesProducedSerializer(TransferSerializerMixin): + CATEGORY_LABEL = 'Bottles produced' + CATEGORY_INDEX_NAME = slugify(CATEGORY_LABEL) - bottles_produced = serializers.IntegerField() + bottles_produced = serializers.CharField() class Meta: model = tag_models.Tag @@ -55,28 +75,37 @@ class BottlesProducedSerializer(TransferSerializerMixin): def validate(self, attrs): value = attrs.pop('bottles_produced') - attrs['label'] = {settings.FALLBACK_LOCALE: value} - attrs['value'] = slugify(value) + parsed_value = self.parsed_value(value) + attrs['label'] = {settings.FALLBACK_LOCALE: parsed_value} + attrs['value'] = slugify(parsed_value) attrs['category'] = self.tag_category return attrs - @property - def tag_category(self): - qs = tag_models.TagCategory.objects.filter(index_name=self.TAG_CATEGORY) - if qs.exists(): - return qs.first() + def parsed_value(self, value): + if value.isdigit(): + return int(value) + + parted = value.split(' ') + if len(parted) > 1: + values = [int(i) if i.isdigit() else 0 for i in parted] + return reduce(lambda a, b: a + b, values) + + lowered = value.lower() + if 'magnum' in lowered: + return 1 + + return 0 -class WineStandardSerializer(TransferSerializerMixin): +class ProductStandardSerializer(TransferSerializerMixin): id = serializers.IntegerField() name = serializers.CharField() - type = serializers.ChoiceField(choices=models.WineStandard.STANDARDS, - allow_null=True) + type = serializers.CharField(allow_null=True) longitude = serializers.FloatField(allow_null=True) latitude = serializers.FloatField(allow_null=True) class Meta: - model = models.WineStandard + model = models.ProductStandard fields = ( 'id', 'name', @@ -88,23 +117,53 @@ class WineStandardSerializer(TransferSerializerMixin): def validate(self, attrs): latitude = attrs.pop('latitude', None) longitude = attrs.pop('longitude', None) + standard_type = attrs.pop('type', None) attrs['coordinates'] = get_point_from_coordinates(latitude, longitude) attrs['old_id'] = attrs.get('id') - attrs['standard_type'] = attrs.pop('type', None) + attrs['standard_type'] = self.get_standard_type(standard_type) return attrs + def get_standard_type(self, type: str): + if type == 'Appellation': + return models.ProductStandard.APPELLATION + elif type == 'YardClassification': + return models.ProductStandard.WINEQUALITY + elif type == 'WineQuality': + return models.ProductStandard.YARDCLASSIFICATION -class WineStandardClassificationSerializer(serializers.ModelSerializer): + +class WineClassificationTypeSerializer(TransferSerializerMixin): + + name = serializers.CharField() + + class Meta: + model = models.ProductClassificationType + fields = ( + 'name', + ) + + def validate(self, attrs): + attrs['product_type'] = self.wine_type + return attrs + + @property + def wine_type(self): + qs = models.ProductType.objects.filter(index_name=models.ProductType.WINE) + if qs.exists(): + return qs.first() + + +class ProductClassificationSerializer(TransferSerializerMixin): id = serializers.IntegerField() name = serializers.CharField() possible_type_id = serializers.IntegerField(allow_null=True) - possible_color_id = serializers.IntegerField() - parent_id = serializers.IntegerField() + possible_color_id = serializers.IntegerField(allow_null=True) + parent_id = serializers.IntegerField(allow_null=True) class Meta: - model = models.WineClassification + model = models.ProductClassification fields = ( 'id', 'name', @@ -114,40 +173,56 @@ class WineStandardClassificationSerializer(serializers.ModelSerializer): ) def validate(self, attrs): + classification_name = attrs.pop('name') possible_type_id = attrs.pop('possible_type_id', None) possible_color_id = attrs.pop('possible_color_id', None) parent_id = attrs.pop('parent_id', None) + attrs['old_id'] = attrs.pop('id') - attrs['possible_subtype'] = self.get_possible_type(possible_type_id) + attrs['classification_type'] = self.get_classification_type(classification_name) + attrs['possible_subtype_tag'] = self.get_possible_type_tag(possible_type_id) attrs['possible_color_tag'] = self.get_possible_color_tag(possible_color_id) attrs['standard'] = self.get_wine_standard(parent_id) return attrs def create(self, validated_data): possible_color_tag = validated_data.pop('possible_color_tag', None) - obj = super().create(validated_data) + possible_subtype_tag = validated_data.pop('possible_subtype_tag', None) + obj, _ = self.Meta.model.objects.get_or_create(**validated_data) if possible_color_tag: obj.tags.add(possible_color_tag) + if possible_subtype_tag: + obj.tags.add(possible_subtype_tag) return obj - def get_possible_type(self, possible_type_id): - legacy_qs = transfer_models.WineClassification.objects.filter(id=possible_type_id) - if legacy_qs.exists(): - qs = models.ProductSubType.objects.filter(index_name=legacy_qs.first()) + def get_classification_type(self, classification_name): + qs = models.ProductClassificationType.objects.filter(name__icontains=classification_name) + if qs.exists(): + return qs.first() + + def get_possible_type_tag(self, possible_type_id): + if possible_type_id: + qs = tag_models.Tag.objects.filter( + old_id=possible_type_id, + category__index_name=WineTypeSerializer.CATEGORY_INDEX_NAME) + if qs.exists(): + return qs.first() + else: + import ipdb; ipdb.set_trace() + + def get_possible_color_tag(self, possible_color_id): + if possible_color_id: + qs = tag_models.Tag.objects.filter( + old_id=possible_color_id, + category__index_name=WineColorSerializer.CATEGORY_INDEX_NAME) if qs.exists(): return qs.first() - def get_possible_color_tag(self, possible_color_id): - qs = tag_models.Tag.objects.filter( - old_id=possible_color_id, - category__index_name=slugify(WineColorSerializer.TAG_CATEGORY)) - if qs.exists(): - return qs.first() - def get_wine_standard(self, parent_id): - qs = models.WineStandard.objects.filter(old_id=parent_id) - if qs.exists(): - return qs.first() + if parent_id: + qs = models.ProductStandard.objects.filter(old_id=parent_id) + if qs.exists(): + return qs.first() class ProductBrandSerializer(TransferSerializerMixin): @@ -171,7 +246,7 @@ class ProductSerializer(TransferSerializerMixin): queryset=transfer_models.Establishments.objects.all(), allow_null=True) classification_id = serializers.PrimaryKeyRelatedField( - queryset=transfer_models.WineClassification.objects.all(), + queryset=transfer_models.ProductClassification.objects.all(), allow_null=True) wine_region_id = serializers.PrimaryKeyRelatedField( queryset=transfer_models.WineLocations.objects.all(), @@ -183,7 +258,7 @@ class ProductSerializer(TransferSerializerMixin): queryset=transfer_models.WineColor.objects.all(), allow_null=True) appellation_id = serializers.PrimaryKeyRelatedField( - queryset=transfer_models.WineClassification.objects.all(), + queryset=transfer_models.ProductClassification.objects.all(), allow_null=True) village_id = serializers.PrimaryKeyRelatedField( queryset=transfer_models.WineLocations.objects.all(), @@ -192,58 +267,84 @@ class ProductSerializer(TransferSerializerMixin): queryset=transfer_models.WineLocations.objects.all(), allow_null=True) wine_quality_id = serializers.PrimaryKeyRelatedField( - queryset=transfer_models.WineClassification.objects.all(), + queryset=transfer_models.ProductClassification.objects.all(), allow_null=True) brand = serializers.CharField(allow_null=True) name = serializers.CharField(allow_null=True) vintage = serializers.CharField(allow_null=True) type = serializers.CharField(allow_null=True) - price = serializers.CharField(allow_null=True) - average_price_in_shops = serializers.CharField(allow_null=True) wine_sub_region_id = serializers.CharField(allow_null=True) state = serializers.CharField() bottles_produced = serializers.CharField(allow_null=True) + unique_key = serializers.CharField(allow_null=True) class Meta: model = models.Product fields = ( - 'establishment_id', - 'classification_id', - 'wine_region_id', - 'wine_type_id', - 'wine_color_id', - 'appellation_id', - 'village_id', - 'vineyard_id', - 'wine_quality_id', - 'brand', - 'name', - 'vintage', - 'type', - 'price', - 'average_price_in_shops', - 'wine_sub_region_id', - 'state', - 'bottles_produced', + 'establishment_id', # done + 'classification_id', # done + 'wine_region_id', # done + 'wine_type_id', # done + 'wine_color_id', # done + 'appellation_id', # done + 'village_id', # done + # 'vineyard_id', duplicate wine_village + 'wine_quality_id', # done + 'brand', # done + 'name', # done + 'vintage', # done + 'type', # done + 'wine_sub_region_id', # done + 'state', # done + 'bottles_produced', # done + 'unique_key', # done ) def validate(self, attrs): - establishment_old_id = attrs.pop('establishment_id', None) + establishment = attrs.pop('establishment_id', None) state = attrs.pop('state', None) brand = attrs.pop('brand', None) + classification = attrs.pop('classification_id', None) + vintage = attrs.pop('vintage_year', None) + product_type = attrs.pop('type') + wine_region = attrs.pop('wine_region_id', None) + wine_sub_region_id = attrs.pop('wine_sub_region_id', None) + bottles_produced = attrs.pop('bottles_produced', None) + wine_type = attrs.pop('wine_type_id', None) + wine_color = attrs.pop('wine_color_id', None) + appellation = attrs.pop('appellation_id', None) + village = attrs.pop('village_id', None) + wine_quality = attrs.pop('wine_quality_id', None) - attrs['establishment'] = self.get_establishment(establishment_old_id) + attrs['old_unique_key'] = attrs.pop('unique_key') + attrs['establishment'] = self.get_establishment(establishment) attrs['state'] = self.get_state(state) attrs['brand'] = self.get_brand(brand) - import ipdb; ipdb.set_trace() + attrs['wine_classification'] = self.get_wine_classification(classification) + attrs['wine_quiality'] = self.get_wine_standard(classification, + models.ProductStandard.WINEQUALITY) + attrs['wine_appellation'] = self.get_wine_standard(appellation, + models.ProductStandard.APPELLATION) + attrs['product_type'] = self.get_product_type(product_type) + attrs['vintage'] = self.get_vintage_year(vintage) + attrs['wine_region'] = self.get_wine_region(wine_region) + attrs['wine_sub_region'] = self.get_wine_sub_region(wine_sub_region_id) + attrs['bottles_produced_tag'] = self.get_tag(bottles_produced, + WineBottlesProducedSerializer.CATEGORY_INDEX_NAME) + attrs['wine_type_tag'] = self.get_tag(wine_type, + WineTypeSerializer.CATEGORY_INDEX_NAME) + attrs['wine_color_tag'] = self.get_tag(wine_color, + WineColorSerializer.CATEGORY_INDEX_NAME) + attrs['wine_village'] = self.get_wine_village(village) return attrs - def get_establishment(self, establishment_old_id): - qs = establishment_models.Establishment.objects.filter( - old_id=establishment_old_id) - if qs.exists(): - return qs.first() + def get_establishment(self, establishment): + if establishment: + qs = establishment_models.Establishment.objects.filter( + old_id=establishment.id) + if qs.exists(): + return qs.first() def get_state(self, state): if state == 'published': @@ -253,6 +354,80 @@ class ProductSerializer(TransferSerializerMixin): return models.Product.WAITING def get_brand(self, brand): - qs = models.ProductBrand.objects.filter(brand__icontains=brand) - if qs.exists(): - return qs.first() + if brand: + qs = models.ProductBrand.objects.filter(brand__icontains=brand) + if qs.exists(): + return qs.first() + + def get_wine_classification(self, classification): + if classification: + classification_qs = models.ProductClassification.objects.filter( + old_id=classification.id) + if classification_qs.exists(): + return classification_qs.first() + + def get_vintage_year(self, vintage): + if vintage.isdigit(): + if len(vintage) == 2: + if vintage == '16': + return 2016 + elif len(vintage) == 4: + if 1900 < int(vintage) < 2100: + return int(vintage) + elif vintage == '1584': + return 1984 + elif vintage == '1017': + return 2017 + elif len(vintage) == 5: + if vintage == '20115': + return 2015 + elif vintage == '20174': + return 2017 + elif vintage.endswith('er'): + return self.get_vintage_year(vintage[:-2]) + + def get_product_type_tag(self, product_type): + if product_type: + qs = models.ProductType.objects.filter( + index_name__icontains=product_type) + if qs.exists(): + return qs.first() + + def get_wine_region(self, wine_region): + if wine_region: + wine_region_qs = location_models.WineRegion.objects.filter( + old_id=wine_region.id) + if wine_region_qs.exists(): + return wine_region_qs.first() + + def get_wine_sub_region(self, wine_sub_region_id): + if wine_sub_region_id: + sub_region_qs = location_models.WineSubRegion.objects.filter( + old_id=wine_sub_region_id) + if sub_region_qs.exists(): + return sub_region_qs.first() + + def get_wine_village(self, village): + if village: + village_qs = location_models.WineVillage.objects.filter( + old_id=village.id) + if village_qs.exists(): + return village_qs.first() + + def get_tag(self, tag, category_index_name: str): + tag = tag.value if hasattr(tag, 'value') else tag + if tag: + qs = tag_models.Tag.objects.filter( + value=tag, + category__index_name=category_index_name) + if qs.exists(): + return qs.first() + + def get_wine_standard(self, standard, standard_type): + if standard: + standard = standard.id if hasattr(standard, 'id') else standard + standard_qs = models.ProductStandard.objects.filter( + standard_type=standard_type, + old_id=standard.id) + if standard_qs.exists(): + return standard_qs.first() \ No newline at end of file