diff --git a/apps/location/models.py b/apps/location/models.py index 7bdd0cc4..cca1371a 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -164,9 +164,15 @@ class WineRegion(models.Model): """Wine region model.""" name = models.CharField(_('name'), max_length=255) country = models.ForeignKey(Country, on_delete=models.PROTECT, + blank=True, null=True, default=None, verbose_name=_('country')) coordinates = models.PointField( _('Coordinates'), blank=True, null=True, default=None) + old_id = models.PositiveIntegerField(_('old id'), default=None, + blank=True, null=True) + description = TJSONField(blank=True, null=True, default=None, + verbose_name=_('description'), + help_text='{"en-GB":"some text"}') objects = WineRegionQuerySet.as_manager() @@ -183,8 +189,10 @@ class WineSubRegionQuerySet(models.QuerySet): class WineSubRegion(models.Model): """Wine sub region model.""" name = models.CharField(_('name'), max_length=255) - country = models.ForeignKey(Country, on_delete=models.PROTECT, - verbose_name=_('country')) + wine_region = models.ForeignKey(WineRegion, on_delete=models.PROTECT, + verbose_name=_('wine sub region')) + old_id = models.PositiveIntegerField(_('old id'), default=None, + blank=True, null=True) objects = WineSubRegionQuerySet.as_manager() @@ -204,12 +212,10 @@ class WineVillage(models.Model): Description: Imported from legacy DB. """ name = models.CharField(_('name'), max_length=255) - description = TJSONField(verbose_name=_('description'), - help_text='{"en-GB":"some text"}') wine_region = models.ForeignKey(WineRegion, on_delete=models.PROTECT, verbose_name=_('wine region')) - wine_sub_region = models.ForeignKey(WineSubRegion, on_delete=models.PROTECT, - verbose_name=_('wine sub region')) + old_id = models.PositiveIntegerField(_('old id'), default=None, + blank=True, null=True) objects = WineVillageQuerySet.as_manager() diff --git a/apps/location/transfer_data.py b/apps/location/transfer_data.py index cb8402ad..d2112826 100644 --- a/apps/location/transfer_data.py +++ b/apps/location/transfer_data.py @@ -1,14 +1,13 @@ -from transfer.serializers.location import CountrySerializer, RegionSerializer, \ - CitySerializer, AddressSerializer, \ - Country -from transfer.models import Cities, Locations +from transfer.serializers import location as location_serializers +from transfer import models as transfer_models +from location.models import Country from pprint import pprint from requests import get def transfer_countries(): - queryset = Cities.objects.raw(""" + queryset = transfer_models.Cities.objects.raw(""" SELECT cities.id, cities.country_code_2 FROM cities WHERE country_code_2 IS NOT NULL AND @@ -18,7 +17,7 @@ def transfer_countries(): queryset = [vars(query) for query in queryset] - serialized_data = CountrySerializer(data=queryset, many=True) + serialized_data = location_serializers.CountrySerializer(data=queryset, many=True) if serialized_data.is_valid(): serialized_data.save() else: @@ -26,7 +25,7 @@ def transfer_countries(): def transfer_regions(): - regions_without_subregion_queryset = Cities.objects.raw(""" + regions_without_subregion_queryset = transfer_models.Cities.objects.raw(""" SELECT cities.id, cities.region_code, cities.country_code_2, @@ -47,13 +46,14 @@ def transfer_regions(): regions_without_subregion_queryset = [vars(query) for query in regions_without_subregion_queryset] - serialized_without_subregion = RegionSerializer(data=regions_without_subregion_queryset, many=True) + serialized_without_subregion = location_serializers.RegionSerializer(data=regions_without_subregion_queryset, + many=True) if serialized_without_subregion.is_valid(): serialized_without_subregion.save() else: pprint(f"Parent regions serializer errors: {serialized_without_subregion.errors}") - regions_with_subregion_queryset = Cities.objects.raw(""" + regions_with_subregion_queryset = transfer_models.Cities.objects.raw(""" SELECT cities.id, cities.region_code, @@ -84,7 +84,8 @@ def transfer_regions(): regions_with_subregion_queryset = [vars(query) for query in regions_with_subregion_queryset] - serialized_with_subregion = RegionSerializer(data=regions_with_subregion_queryset, many=True) + serialized_with_subregion = location_serializers.RegionSerializer(data=regions_with_subregion_queryset, + many=True) if serialized_with_subregion.is_valid(): serialized_with_subregion.save() else: @@ -92,7 +93,7 @@ def transfer_regions(): def transfer_cities(): - queryset = Cities.objects.raw("""SELECT cities.id, cities.name, cities.country_code_2, cities.zip_code, + queryset = transfer_models.Cities.objects.raw("""SELECT cities.id, cities.name, cities.country_code_2, cities.zip_code, cities.is_island, cities.region_code, cities.subregion_code FROM cities WHERE region_code IS NOT NULL AND @@ -103,7 +104,7 @@ def transfer_cities(): queryset = [vars(query) for query in queryset] - serialized_data = CitySerializer(data=queryset, many=True) + serialized_data = location_serializers.CitySerializer(data=queryset, many=True) if serialized_data.is_valid(): serialized_data.save() else: @@ -111,7 +112,7 @@ def transfer_cities(): def transfer_addresses(): - queryset = Locations.objects.raw("""SELECT locations.id, locations.zip_code, locations.longitude, + queryset = transfer_models.Locations.objects.raw("""SELECT locations.id, locations.zip_code, locations.longitude, locations.latitude, locations.address, locations.city_id FROM locations WHERE locations.address != "" AND @@ -126,13 +127,46 @@ def transfer_addresses(): queryset = [vars(query) for query in queryset] - serialized_data = AddressSerializer(data=queryset, many=True) + serialized_data = location_serializers.AddressSerializer(data=queryset, many=True) if serialized_data.is_valid(): serialized_data.save() else: pprint(f"Address serializer errors: {serialized_data.errors}") +def transfer_wine_region(): + queryset = transfer_models.WineLocations.objects.filter(type='WineRegion') + serialized_data = location_serializers.WineRegion( + data=list(queryset.values()), + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + pprint(f"WineStandardClassificationSerializer errors: {serialized_data.errors}") + + +def transfer_wine_sub_region(): + queryset = transfer_models.WineLocations.objects.filter(type='WineSubRegion') + serialized_data = location_serializers.WineSubRegion( + data=list(queryset.values()), + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + pprint(f"WineStandardClassificationSerializer errors: {serialized_data.errors}") + + +def transfer_wine_village(): + queryset = transfer_models.WineLocations.objects.filter(type='Village') + serialized_data = location_serializers.WineVillage( + data=list(queryset.values()), + many=True) + if serialized_data.is_valid(): + serialized_data.save() + else: + pprint(f"WineStandardClassificationSerializer errors: {serialized_data.errors}") + + def update_flags(): queryset = Country.objects.only("id", "code", "svg_image").filter(old_id__isnull=False) link_to_request = "https://s3.eu-central-1.amazonaws.com/gm-test.com/media" @@ -148,11 +182,14 @@ def update_flags(): data_types = { "dictionaries": [ transfer_countries, - transfer_regions, - transfer_cities, - transfer_addresses + # transfer_regions, + # transfer_cities, + # transfer_addresses, + transfer_wine_region, + transfer_wine_sub_region, + transfer_wine_village, ], "update_country_flag": [ update_flags - ] + ], } diff --git a/apps/product/models.py b/apps/product/models.py index 3f146731..bde29905 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -168,6 +168,8 @@ class Product(TranslatedFieldsMixin, BaseAttributes): slug = models.SlugField(unique=True, max_length=255, null=True, verbose_name=_('Establishment slug')) favorites = generic.GenericRelation(to='favorites.Favorites') + old_id = models.PositiveIntegerField(_('old id'), default=None, + blank=True, null=True) objects = ProductManager.from_queryset(ProductQuerySet)() diff --git a/apps/transfer/mixins.py b/apps/transfer/mixins.py index a8e8287a..46ed0477 100644 --- a/apps/transfer/mixins.py +++ b/apps/transfer/mixins.py @@ -1,5 +1,6 @@ from django.db import models from django.forms.models import model_to_dict +from rest_framework import serializers class SecondDbManager(models.Manager): @@ -24,3 +25,12 @@ class MigrateMixin(models.Model): class Meta: abstract = True + + +class TransferSerializerMixin(serializers.ModelSerializer): + """Mixin for transferring legacy db models.""" + + def create(self, validated_data): + qs = self.Meta.model.objects.filter(**validated_data) + if not qs.exists(): + return super().create(validated_data) diff --git a/apps/transfer/models.py b/apps/transfer/models.py index f2120ea7..850bd201 100644 --- a/apps/transfer/models.py +++ b/apps/transfer/models.py @@ -1015,3 +1015,18 @@ class MetadatumAliases(MigrateMixin): class Meta: managed = False db_table = 'metadatum_aliases' + + +class WineLocations(MigrateMixin): + using = 'legacy' + + name = models.CharField(max_length=255) + desc = models.TextField(null=True) + latitude = models.FloatField(null=True) + longitude = models.FloatField(null=True) + type = models.CharField(max_length=255) + parent_id = models.IntegerField() + + class Meta: + managed = False + db_table = 'wine_locations' diff --git a/apps/transfer/serializers/location.py b/apps/transfer/serializers/location.py index 4e05897d..b3f49f3c 100644 --- a/apps/transfer/serializers/location.py +++ b/apps/transfer/serializers/location.py @@ -1,8 +1,10 @@ -from rest_framework import serializers -from location.models import Country, Region, City, Address +from django.conf import settings from django.contrib.gis.geos import Point -from django.contrib.gis.geos import GEOSGeometry -import json +from rest_framework import serializers + +from location import models +from transfer.mixins import TransferSerializerMixin +from utils.methods import get_point_from_coordinates class CountrySerializer(serializers.ModelSerializer): @@ -10,7 +12,7 @@ class CountrySerializer(serializers.ModelSerializer): id = serializers.IntegerField() class Meta: - model = Country + model = models.Country fields = ( "id", "country_code_2", @@ -27,9 +29,9 @@ class CountrySerializer(serializers.ModelSerializer): def create(self, validated_data): # Some countries already in database try: - country = Country.objects.get(code=validated_data['code']) - except Country.DoesNotExist: - country = Country.objects.create(**validated_data) + country = models.Country.objects.get(code=validated_data['code']) + except models.Country.DoesNotExist: + country = models.Country.objects.create(**validated_data) return country def get_country_code(self, obj): @@ -43,7 +45,7 @@ class RegionSerializer(serializers.ModelSerializer): id = serializers.IntegerField() class Meta: - model = Region + model = models.Region fields = ( "region_code", "country_code_2", @@ -60,9 +62,9 @@ class RegionSerializer(serializers.ModelSerializer): def create(self, validated_data): # Some regions may be already in database try: - region = Region.objects.get(old_id=validated_data['old_id']) - except Region.DoesNotExist: - region = Region.objects.create(**validated_data) + region = models.Region.objects.get(old_id=validated_data['old_id']) + except models.Region.DoesNotExist: + region = models.Region.objects.create(**validated_data) except Exception as e: raise ValueError(f"REGION ERROR: {validated_data}: {e}") return region @@ -71,7 +73,7 @@ class RegionSerializer(serializers.ModelSerializer): print(data) if "subregion_code" in data and data["subregion_code"] is not None and data["subregion_code"].strip() != "": try: - parent_region = Region.objects.filter(code=str(data['region_code'])).first() + parent_region = models.Region.objects.filter(code=str(data['region_code'])).first() except Exception as e: raise ValueError(f"Parent region error with {data}: {e}") @@ -86,7 +88,7 @@ class RegionSerializer(serializers.ModelSerializer): def set_country(self, data): try: - country = Country.objects.get(code=data['country_code_2']) + country = models.Country.objects.get(code=data['country_code_2']) except Exception as e: raise ValueError(f"Country error with {data}: {e}") @@ -110,7 +112,7 @@ class CitySerializer(serializers.ModelSerializer): id = serializers.IntegerField() class Meta: - model = City + model = models.City fields = ( "country_code_2", "region_code", @@ -130,7 +132,7 @@ class CitySerializer(serializers.ModelSerializer): return data def create(self, validated_data): - return City.objects.create(**validated_data) + return models.City.objects.create(**validated_data) def set_is_island(self, data): data['is_island'] = True if "is_island" in data \ @@ -145,19 +147,19 @@ class CitySerializer(serializers.ModelSerializer): def set_relations(self, data): try: - region = Region.objects.filter(code=data['region_code']).first() - except Region.DoesNotExist as e: + region = models.Region.objects.filter(code=data['region_code']).first() + except models.Region.DoesNotExist as e: try: - region = Region.objects.filter(code=data['subregion_code']).first() - except Region.DoesNotExist as e: + region = models.Region.objects.filter(code=data['subregion_code']).first() + except models.Region.DoesNotExist as e: raise ValueError(f"Region not found with {data}: {e}") data['region'] = region del(data['subregion_code']) try: - country = Country.objects.get(code=data['country_code_2']) - except Country.DoesNotExist as e: + country = models.Country.objects.get(code=data['country_code_2']) + except models.Country.DoesNotExist as e: raise ValueError(f"Country not found with {data}: {e}") data['country'] = country @@ -185,7 +187,7 @@ class AddressSerializer(serializers.ModelSerializer): address = serializers.CharField() class Meta: - model = Address + model = models.Address fields = ( "id", "city_id", @@ -204,7 +206,7 @@ class AddressSerializer(serializers.ModelSerializer): return data def create(self, validated_data): - return Address.objects.create(**validated_data) + return models.Address.objects.create(**validated_data) def set_old_id(self, data): data['old_id'] = data.pop("id") @@ -218,8 +220,8 @@ class AddressSerializer(serializers.ModelSerializer): def set_city(self, data): try: - city = City.objects.filter(old_id=data['city_id']).first() - except City.DoesNotExist as e: + city = models.City.objects.filter(old_id=data['city_id']).first() + except models.City.DoesNotExist as e: raise ValueError(f"City not found with {data}: {e}") data['city'] = city @@ -266,3 +268,84 @@ class AddressSerializer(serializers.ModelSerializer): del(data['longitude']) return data + + +class WineRegion(TransferSerializerMixin): + + id = serializers.IntegerField() + name = serializers.CharField() + desc = serializers.CharField(allow_null=True) + latitude = serializers.FloatField(allow_null=True) + longitude = serializers.FloatField(allow_null=True) + + class Meta: + model = models.WineRegion + fields = ( + 'id', + 'name', + 'desc', + 'latitude', + 'longitude', + ) + + def validate(self, attrs): + latitude = attrs.pop('latitude', None) + longitude = attrs.pop('longitude', None) + + attrs['old_id'] = attrs.pop('id') + attrs['description'] = {settings.FALLBACK_LOCALE: attrs.pop('desc', None)} + attrs['coordinates'] = get_point_from_coordinates(latitude, longitude) + return attrs + + +class WineSubRegion(WineRegion): + + id = serializers.IntegerField() + name = serializers.CharField() + parent_id = serializers.IntegerField() + + class Meta: + model = models.WineSubRegion + fields = ( + 'id', + 'name', + 'parent_id', + ) + + def validate(self, attrs): + parent_id = attrs.pop('parent_id', None) + + attrs['old_id'] = attrs.pop('id') + attrs['wine_region'] = self.get_wine_region(parent_id) + return attrs + + def get_wine_region(self, parent_id): + qs = models.WineRegion.objects.filter(old_id=parent_id) + if qs.exists(): + return qs.first() + + +class WineVillage(TransferSerializerMixin): + + id = serializers.IntegerField() + name = serializers.CharField() + parent_id = serializers.IntegerField() + + class Meta: + model = models.WineVillage + fields = ( + 'id', + 'name', + 'parent_id', + ) + + def validate(self, attrs): + parent_id = attrs.pop('parent_id', None) + attrs['old_id'] = attrs.pop('id') + attrs['wine_region'] = self.get_wine_region(parent_id) + return attrs + + def get_wine_region(self, parent_id): + qs = models.WineRegion.objects.filter(old_id=parent_id) + if qs.exists(): + return qs.first() diff --git a/apps/transfer/serializers/product.py b/apps/transfer/serializers/product.py index 6b984a2d..daa41588 100644 --- a/apps/transfer/serializers/product.py +++ b/apps/transfer/serializers/product.py @@ -1,10 +1,12 @@ -from django.contrib.gis.db.models.fields import Point from rest_framework import serializers + from product import models -from transfer.models import WineColor, WineType, WineClassification +from transfer.models import WineClassification +from utils.methods import get_point_from_coordinates +from transfer.mixins import TransferSerializerMixin -class WineColorSerializer(serializers.ModelSerializer): +class WineColorSerializer(TransferSerializerMixin): NAME = 'wine_color' @@ -30,7 +32,7 @@ class WineColorSerializer(serializers.ModelSerializer): return attrs -class WineStandardSerializer(serializers.ModelSerializer): +class WineStandardSerializer(TransferSerializerMixin): id = serializers.IntegerField() name = serializers.CharField() type = serializers.ChoiceField(choices=models.WineStandard.STANDARDS, @@ -52,17 +54,13 @@ class WineStandardSerializer(serializers.ModelSerializer): latitude = attrs.pop('latitude', None) longitude = attrs.pop('longitude', None) - attrs['coordinates'] = self.get_point(latitude, longitude) + attrs['coordinates'] = get_point_from_coordinates(latitude, longitude) attrs['old_id'] = attrs.get('id') attrs['standard_type'] = attrs.pop('type', None) return attrs - def get_point(self, latitude, longitude): - if latitude and longitude: - return Point(x=longitude, y=latitude, srid=4326) - -class WineStandardClassificationSerializer(serializers.ModelSerializer): +class WineStandardClassificationSerializer(TransferSerializerMixin): id = serializers.IntegerField() name = serializers.CharField() @@ -84,7 +82,7 @@ class WineStandardClassificationSerializer(serializers.ModelSerializer): 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', None) + attrs['old_id'] = attrs.pop('id') attrs['possible_subtype'] = self.get_possible_type(possible_type_id) attrs['possible_color'] = self.get_possible_color(possible_color_id) attrs['standard'] = self.get_wine_standard(parent_id) diff --git a/apps/utils/methods.py b/apps/utils/methods.py index ed4fe7bc..dc027317 100644 --- a/apps/utils/methods.py +++ b/apps/utils/methods.py @@ -7,6 +7,7 @@ import string import requests from django.conf import settings from django.contrib.contenttypes.models import ContentType +from django.contrib.gis.geos import Point from django.http.request import HttpRequest from django.utils.timezone import datetime from rest_framework import status @@ -118,3 +119,8 @@ def absolute_url_decorator(func): else: return url_path return get_absolute_image_url + + +def get_point_from_coordinates(latitude: str, longitude: str): + if latitude and longitude: + return Point(x=longitude, y=latitude, srid=4326)