diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 433ff160..eef4dbe7 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -6,7 +6,7 @@ from rest_framework import serializers from comment import models as comment_models from comment.serializers import common as comment_serializers from establishment import models -from location.serializers import AddressBaseSerializer, CitySerializer, AddressDetailSerializer, \ +from location.serializers import AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer, \ CityShortSerializer from location.serializers import EstablishmentWineRegionBaseSerializer, \ EstablishmentWineOriginBaseSerializer @@ -231,7 +231,7 @@ class EstablishmentEmployeeCreateSerializer(serializers.ModelSerializer): class EstablishmentShortSerializer(serializers.ModelSerializer): """Short serializer for establishment.""" - city = CitySerializer(source='address.city', allow_null=True) + city = CityBaseSerializer(source='address.city', allow_null=True) establishment_type = EstablishmentTypeGeoSerializer() establishment_subtypes = EstablishmentSubTypeBaseSerializer(many=True) currency = CurrencySerializer(read_only=True) @@ -253,7 +253,7 @@ class EstablishmentShortSerializer(serializers.ModelSerializer): class _EstablishmentAddressShortSerializer(serializers.ModelSerializer): """Short serializer for establishment.""" - city = CitySerializer(source='address.city', allow_null=True) + city = CityBaseSerializer(source='address.city', allow_null=True) establishment_type = EstablishmentTypeGeoSerializer() establishment_subtypes = EstablishmentSubTypeBaseSerializer(many=True) address = AddressBaseSerializer(read_only=True) diff --git a/apps/location/migrations/0034_city_image.py b/apps/location/migrations/0034_city_image.py new file mode 100644 index 00000000..9c27287c --- /dev/null +++ b/apps/location/migrations/0034_city_image.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.7 on 2020-01-15 09:45 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('gallery', '0008_merge_20191212_0752'), + ('location', '0033_merge_20191224_0920'), + ] + + operations = [ + migrations.AddField( + model_name='city', + name='image', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='city_image', to='gallery.Image', verbose_name='image instance of model Image'), + ), + ] diff --git a/apps/location/models.py b/apps/location/models.py index cdc9ada5..162e72d2 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -75,7 +75,6 @@ class Country(TranslatedFieldsMixin, return self.id - class RegionQuerySet(models.QuerySet): """QuerySet for model Region.""" @@ -168,7 +167,13 @@ class City(GalleryMixin, models.Model): map_ref = models.CharField(max_length=255, blank=True, null=True) situation = models.CharField(max_length=255, blank=True, null=True) + # deprecated + # todo: remove gallery after move to image gallery = models.ManyToManyField('gallery.Image', through='location.CityGallery', blank=True) + image = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL, + blank=True, null=True, default=None, + related_name='city_image', + verbose_name=_('image instance of model Image')) mysql_id = models.IntegerField(blank=True, null=True, default=None) @@ -181,6 +186,30 @@ class City(GalleryMixin, models.Model): def __str__(self): return self.name + @property + def image_object(self): + """Return image object.""" + return self.image.image if self.image else None + + @property + def crop_image(self): + if hasattr(self, 'image') and hasattr(self, '_meta'): + if self.image: + image_property = { + 'id': self.image.id, + 'title': self.image.title, + 'original_url': self.image.image.url, + 'orientation_display': self.image.get_orientation_display(), + 'auto_crop_images': {}, + } + crop_parameters = [p for p in settings.SORL_THUMBNAIL_ALIASES + if p.startswith(self._meta.model_name.lower())] + for crop in crop_parameters: + image_property['auto_crop_images'].update( + {crop: self.image.get_image_url(crop)} + ) + return image_property + class CityGallery(IntermediateGalleryModelMixin): """Gallery for model City.""" diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 65c30b46..9f8613c4 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -3,7 +3,7 @@ from django.contrib.gis.geos import Point from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from location import models -from utils.serializers import TranslatedField +from utils.serializers import TranslatedField, ImageBaseSerializer class CountrySerializer(serializers.ModelSerializer): @@ -70,7 +70,7 @@ class CityShortSerializer(serializers.ModelSerializer): ) -class CitySerializer(serializers.ModelSerializer): +class CityBaseSerializer(serializers.ModelSerializer): """City serializer.""" region = RegionSerializer(read_only=True) region_id = serializers.PrimaryKeyRelatedField( @@ -99,6 +99,17 @@ class CitySerializer(serializers.ModelSerializer): ] +class CityDetailSerializer(CityBaseSerializer): + """Serializer for detail view.""" + image = ImageBaseSerializer(source='crop_image', read_only=True) + + class Meta(CityBaseSerializer.Meta): + """Meta class.""" + fields = CityBaseSerializer.Meta.fields + [ + 'image', + ] + + class AddressBaseSerializer(serializers.ModelSerializer): """Serializer for address obj in related objects.""" @@ -154,7 +165,7 @@ class AddressDetailSerializer(AddressBaseSerializer): city_id = serializers.PrimaryKeyRelatedField( source='city', write_only=True, queryset=models.City.objects.all()) - city = CitySerializer(read_only=True) + city = CityBaseSerializer(read_only=True) class Meta(AddressBaseSerializer.Meta): """Meta class.""" diff --git a/apps/location/transfer_data.py b/apps/location/transfer_data.py index 54bf2301..ba6c535f 100644 --- a/apps/location/transfer_data.py +++ b/apps/location/transfer_data.py @@ -557,7 +557,7 @@ def remove_old_records(): def transfer_city_gallery(): created_counter = 0 cities_not_exists = {} - gallery_obj_exists_counter = 0 + cities_has_same_image = 0 city_gallery = transfer_models.CityPhotos.objects.exclude(city__isnull=True) \ .exclude(city__country_code_2__isnull=True) \ @@ -565,7 +565,7 @@ def transfer_city_gallery(): .exclude(city__region_code__isnull=True) \ .exclude(city__region_code__iexact='') \ .values_list('city_id', 'attachment_suffix_url') - for old_city_id, image_suffix_url in city_gallery: + for old_city_id, image_suffix_url in tqdm(city_gallery): city = City.objects.filter(old_id=old_city_id) if city.exists(): city = city.first() @@ -575,19 +575,18 @@ def transfer_city_gallery(): 'orientation': Image.HORIZONTAL, 'title': f'{city.name} - {image_suffix_url}', }) - city_gallery, created = CityGallery.objects.get_or_create(image=image, - city=city, - is_main=True) - if created: + if city.image != image: + city.image = image + city.save() created_counter += 1 else: - gallery_obj_exists_counter += 1 + cities_has_same_image += 1 else: cities_not_exists.update({'city_old_id': old_city_id}) print(f'Created: {created_counter}\n' f'City not exists: {cities_not_exists}\n' - f'Already added: {gallery_obj_exists_counter}') + f'City has same image: {cities_has_same_image}') @atomic @@ -796,7 +795,6 @@ def set_unused_regions(): ) - data_types = { "dictionaries": [ # transfer_countries, @@ -824,12 +822,11 @@ data_types = { remove_old_records ], "fill_city_gallery": [ - transfer_city_gallery + transfer_city_gallery, ], "add_fake_country": [ add_fake_country, ], - "setup_clean_db": [setup_clean_db], "set_unused_regions": [set_unused_regions], "update_fake_country_flag": [update_fake_country_flag] diff --git a/apps/location/views/back.py b/apps/location/views/back.py index 125c2b0b..b02c79aa 100644 --- a/apps/location/views/back.py +++ b/apps/location/views/back.py @@ -36,7 +36,7 @@ class AddressRUDView(common.AddressViewMixin, generics.RetrieveUpdateDestroyAPIV # City class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView): """Create view for model City.""" - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityBaseSerializer permission_classes = [IsAuthenticatedOrReadOnly | IsCountryAdmin] queryset = models.City.objects.all() filter_class = filters.CityBackFilter @@ -52,7 +52,7 @@ class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView): class CityListSearchView(common.CityViewMixin, generics.ListCreateAPIView): """Create view for model City.""" - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityBaseSerializer permission_classes = [IsAuthenticatedOrReadOnly | IsCountryAdmin] queryset = models.City.objects.all()\ .annotate(locale_name=KeyTextTransform(get_current_locale(), 'name_translated'))\ @@ -63,7 +63,7 @@ class CityListSearchView(common.CityViewMixin, generics.ListCreateAPIView): class CityRUDView(common.CityViewMixin, generics.RetrieveUpdateDestroyAPIView): """RUD view for model City.""" - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityDetailSerializer permission_classes = [IsAuthenticatedOrReadOnly | IsCountryAdmin] diff --git a/apps/location/views/common.py b/apps/location/views/common.py index 660a1dbe..d9d5520b 100644 --- a/apps/location/views/common.py +++ b/apps/location/views/common.py @@ -85,18 +85,18 @@ class RegionUpdateView(RegionViewMixin, generics.UpdateAPIView): # City class CityCreateView(CityViewMixin, generics.CreateAPIView): """Create view for model City""" - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityBaseSerializer class CityRetrieveView(CityViewMixin, generics.RetrieveAPIView): """Retrieve view for model City""" - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityDetailSerializer class CityListView(CityViewMixin, generics.ListAPIView): """List view for model City""" permission_classes = (permissions.AllowAny,) - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityBaseSerializer def get_queryset(self): qs = super().get_queryset() @@ -107,12 +107,12 @@ class CityListView(CityViewMixin, generics.ListAPIView): class CityDestroyView(CityViewMixin, generics.DestroyAPIView): """Destroy view for model City""" - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityBaseSerializer class CityUpdateView(CityViewMixin, generics.UpdateAPIView): """Update view for model City""" - serializer_class = serializers.CitySerializer + serializer_class = serializers.CityBaseSerializer # Address diff --git a/project/settings/local.py b/project/settings/local.py index a5c0ec8a..2ad132f1 100644 --- a/project/settings/local.py +++ b/project/settings/local.py @@ -43,15 +43,15 @@ DATABASES = { 'options': '-c search_path=gm,public' }, }, - 'legacy': { - 'ENGINE': 'django.db.backends.mysql', - # 'HOST': '172.22.0.1', - 'HOST': 'mysql_db', - 'PORT': 3306, - 'NAME': 'dev', - 'USER': 'dev', - 'PASSWORD': 'octosecret123' - }, + 'legacy': { + 'ENGINE': 'django.db.backends.mysql', + # 'HOST': '172.22.0.1', + 'HOST': 'mysql_db', + 'PORT': 3306, + 'NAME': 'dev', + 'USER': 'dev', + 'PASSWORD': 'octosecret123' + }, } @@ -84,11 +84,11 @@ LOGGING = { 'py.warnings': { 'handlers': ['console'], }, - 'django.db.backends': { - 'handlers': ['console', ], - 'level': 'DEBUG', - 'propagate': False, - }, + # 'django.db.backends': { + # 'handlers': ['console', ], + # 'level': 'DEBUG', + # 'propagate': False, + # }, } } diff --git a/requirements/base.txt b/requirements/base.txt index f5bbf2d5..25a0256c 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -49,7 +49,6 @@ django-storages==1.7.2 sorl-thumbnail==12.5.0 - PyYAML==5.1.2 # temp solution diff --git a/requirements/development.txt b/requirements/development.txt index 77c3d73c..4763063b 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -1,4 +1,8 @@ -r base.txt ipdb ipython -mysqlclient==1.4.4 \ No newline at end of file +mysqlclient==1.4.4 + +pyparsing +graphviz +pydot \ No newline at end of file