diff --git a/.gitignore b/.gitignore index 90e4f23f..26d44a44 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ celerybeat.pid /gm_viktor.dump /docker-compose.dump.yml /gm_production_20191029.sql +/apps/transfer/log diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index aa3c991a..da9ded41 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -65,7 +65,7 @@ class CollectionEstablishmentListView(CollectionListView): # May raise a permission denied self.check_object_permissions(self.request, collection) - return collection.establishments.all().annotate_in_favorites(self.request.user) + return collection.establishments.published().annotate_in_favorites(self.request.user) # Guide diff --git a/apps/establishment/filters.py b/apps/establishment/filters.py index db419989..6dd70222 100644 --- a/apps/establishment/filters.py +++ b/apps/establishment/filters.py @@ -13,6 +13,8 @@ class EstablishmentFilter(filters.FilterSet): search = filters.CharFilter(method='search_text') type = filters.CharFilter(method='by_type') subtype = filters.CharFilter(method='by_subtype') + city_id = filters.CharFilter(field_name='address__city__id') + city_name = filters.CharFilter(field_name='address__city__name') class Meta: """Meta class.""" @@ -24,6 +26,8 @@ class EstablishmentFilter(filters.FilterSet): 'search', 'type', 'subtype', + 'city_id', + 'city_name', ) def search_text(self, queryset, name, value): diff --git a/apps/establishment/models.py b/apps/establishment/models.py index d4c31579..be932d84 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -132,7 +132,8 @@ class EstablishmentQuerySet(models.QuerySet): def with_extended_address_related(self): """Return qs with deeply related address models.""" - return self.select_related('address__city', 'address__city__region', 'address__city__region__country', + return self.select_related('address__city', 'address__city__region', + 'address__city__region__country', 'address__city__country') def with_extended_related(self): @@ -147,7 +148,8 @@ class EstablishmentQuerySet(models.QuerySet): def with_es_related(self): """Return qs with related for ES indexing objects.""" - return self.select_related('address', 'establishment_type', 'address__city', 'address__city__country'). \ + return self.select_related('address', 'establishment_type', 'address__city', + 'address__city__country'). \ prefetch_related('tags', 'schedule') def search(self, value, locale=None): @@ -246,11 +248,12 @@ class EstablishmentQuerySet(models.QuerySet): 'address__city__country': establishment.address.city.country } if establishment.establishment_subtypes.exists(): - filters.update({'establishment_subtypes__in': establishment.establishment_subtypes.all()}) + filters.update( + {'establishment_subtypes__in': establishment.establishment_subtypes.all()}) return self.exclude(id=establishment.id) \ - .filter(**filters) \ - .annotate_distance(point=establishment.location) + .filter(**filters) \ + .annotate_distance(point=establishment.location) def similar_base_subquery(self, establishment, filters: dict) -> Subquery: """ @@ -283,10 +286,10 @@ class EstablishmentQuerySet(models.QuerySet): ) # todo: fix this - replace ids_by_subquery.queryset on ids_by_subquery return self.filter(id__in=ids_by_subquery.queryset) \ - .annotate_intermediate_public_mark() \ - .annotate_mark_similarity(mark=restaurant.public_mark) \ - .order_by('mark_similarity') \ - .distinct('mark_similarity', 'id') + .annotate_intermediate_public_mark() \ + .annotate_mark_similarity(mark=restaurant.public_mark) \ + .order_by('mark_similarity') \ + .distinct('mark_similarity', 'id') def same_subtype(self, establishment): """Annotate flag same subtype.""" @@ -305,11 +308,11 @@ class EstablishmentQuerySet(models.QuerySet): :param establishment: Establishment instance """ return self.similar_base(establishment) \ - .same_subtype(establishment) \ - .has_published_reviews() \ - .order_by(F('same_subtype').desc(), - F('distance').asc()) \ - .distinct('same_subtype', 'distance', 'id') + .same_subtype(establishment) \ + .has_published_reviews() \ + .order_by(F('same_subtype').desc(), + F('distance').asc()) \ + .distinct('same_subtype', 'distance', 'id') def by_wine_region(self, wine_region): """ @@ -331,13 +334,13 @@ class EstablishmentQuerySet(models.QuerySet): :param winery: Establishment instance """ return self.similar_base(winery) \ - .order_by(F('wine_origins__wine_region').asc(), - F('wine_origins__wine_sub_region').asc(), - F('distance').asc()) \ - .distinct('wine_origins__wine_region', - 'wine_origins__wine_sub_region', - 'distance', - 'id') + .order_by(F('wine_origins__wine_region').asc(), + F('wine_origins__wine_sub_region').asc(), + F('distance').asc()) \ + .distinct('wine_origins__wine_region', + 'wine_origins__wine_sub_region', + 'distance', + 'id') def last_reviewed(self, point: Point): """ @@ -495,10 +498,6 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, schedule = models.ManyToManyField(to='timetable.Timetable', blank=True, verbose_name=_('Establishment schedule'), related_name='schedule') - # holidays_from = models.DateTimeField(verbose_name=_('Holidays from'), - # help_text=_('Holidays closing date from')) - # holidays_to = models.DateTimeField(verbose_name=_('Holidays to'), - # help_text=_('Holidays closing date to')) transportation = models.TextField(blank=True, null=True, default=None, verbose_name=_('Transportation')) collections = models.ManyToManyField(to='collection.Collection', @@ -558,7 +557,7 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, .exclude(category__index_name__in=['guide', 'collection', 'purchased_item', 'business_tag', 'business_tags_de']) \ .exclude(value__in=['rss', 'rss_selection']) - # todo: recalculate toque_number + # todo: recalculate toque_number @property def visible_tags_detail(self): @@ -592,13 +591,6 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, country = self.address.city.country return country.low_price, country.high_price - # todo: make via prefetch - # @property - # def subtypes(self): - # return EstablishmentSubType.objects.filter( - # subtype_establishment=self, - # establishment_type=self.establishment_type, - # establishment_type__use_subtypes=True) def set_establishment_type(self, establishment_type): self.establishment_type = establishment_type @@ -925,6 +917,12 @@ class EmployeeQuerySet(models.QuerySet): """Search by name or last_name.""" return self._generic_search(value, ['name', 'last_name']) + def actual_establishment(self): + e = EstablishmentEmployee.objects.actual().filter(employee=self) + return self.prefetch_related(models.Prefetch('establishmentemployee_set', + queryset=EstablishmentEmployee.objects.actual() + )).all().distinct() + class Employee(BaseAttributes): """Employee model.""" @@ -933,7 +931,8 @@ class Employee(BaseAttributes): null=True, blank=True, default=None, verbose_name=_('User')) name = models.CharField(max_length=255, verbose_name=_('Name')) - last_name = models.CharField(max_length=255, verbose_name=_('Last Name'), null=True, default=None) + last_name = models.CharField(max_length=255, verbose_name=_('Last Name'), null=True, + default=None) # SEX CHOICES MALE = 0 @@ -943,11 +942,14 @@ class Employee(BaseAttributes): (MALE, _('Male')), (FEMALE, _('Female')) ) - sex = models.PositiveSmallIntegerField(choices=SEX_CHOICES, verbose_name=_('Sex'), null=True, default=None) - birth_date = models.DateTimeField(editable=True, verbose_name=_('Birth date'), null=True, default=None) + sex = models.PositiveSmallIntegerField(choices=SEX_CHOICES, verbose_name=_('Sex'), null=True, + default=None) + birth_date = models.DateTimeField(editable=True, verbose_name=_('Birth date'), null=True, + default=None) email = models.EmailField(blank=True, null=True, default=None, verbose_name=_('Email')) phone = PhoneNumberField(null=True, default=None) - toque_number = models.PositiveSmallIntegerField(verbose_name=_('Toque number'), null=True, default=None) + toque_number = models.PositiveSmallIntegerField(verbose_name=_('Toque number'), null=True, + default=None) establishments = models.ManyToManyField(Establishment, related_name='employees', through=EstablishmentEmployee, ) @@ -998,25 +1000,6 @@ class ContactEmail(models.Model): return f'{self.email}' -# -# class Wine(TranslatedFieldsMixin, models.Model): -# """Wine model.""" -# establishment = models.ForeignKey( -# 'establishment.Establishment', verbose_name=_('establishment'), -# on_delete=models.CASCADE) -# bottles = models.IntegerField(_('bottles')) -# price_min = models.DecimalField( -# _('price min'), max_digits=14, decimal_places=2) -# price_max = models.DecimalField( -# _('price max'), max_digits=14, decimal_places=2) -# by_glass = models.BooleanField(_('by glass')) -# price_glass_min = models.DecimalField( -# _('price min'), max_digits=14, decimal_places=2) -# price_glass_max = models.DecimalField( -# _('price max'), max_digits=14, decimal_places=2) -# - - class Plate(TranslatedFieldsMixin, models.Model): """Plate model.""" STR_FIELD_NAME = 'name' diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index fbdd7a10..54a33c5a 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -157,28 +157,6 @@ class ContactEmailBackSerializers(model_serializers.PlateSerializer): ] -# TODO: test decorator -@with_base_attributes -class EmployeeBackSerializers(serializers.ModelSerializer): - """Employee serializers.""" - - awards = AwardSerializer(many=True, read_only=True) - - class Meta: - model = models.Employee - fields = [ - 'id', - 'user', - 'name', - 'last_name', - 'sex', - 'birth_date', - 'email', - 'phone', - 'toque_number', - 'awards', - ] - class PositionBackSerializer(serializers.ModelSerializer): """Position Back serializer.""" @@ -194,6 +172,64 @@ class PositionBackSerializer(serializers.ModelSerializer): 'index_name', ] +# TODO: test decorator +@with_base_attributes +class EmployeeBackSerializers(serializers.ModelSerializer): + """Employee serializers.""" + public_mark = serializers.SerializerMethodField() + positions = serializers.SerializerMethodField() + establishment = serializers.SerializerMethodField() + awards = AwardSerializer(many=True, read_only=True) + + + def get_public_mark(self, obj): + """Get last list actual public_mark""" + qs = obj.establishmentemployee_set.actual().order_by('-from_date')\ + .values('establishment__public_mark').first() + return qs['establishment__public_mark'] + + + def get_positions(self, obj): + """Get last list actual positions""" + est_id = obj.establishmentemployee_set.actual().\ + order_by('-from_date').first().establishment_id + + qs = obj.establishmentemployee_set.actual()\ + .filter(establishment_id=est_id)\ + .prefetch_related('position').values('position') + + positions = models.Position.objects.filter(id__in=[q['position'] for q in qs]) + + return [PositionBackSerializer(p).data for p in positions] + + def get_establishment(self, obj): + """Get last actual establishment""" + est = obj.establishmentemployee_set.actual().order_by('-from_date')\ + .first().establishment + + return { + "id": est.id, + "slug": est.slug + } + + class Meta: + model = models.Employee + fields = [ + 'id', + 'name', + 'last_name', + 'user', + 'public_mark', + 'positions', + 'awards', + 'establishment', + 'sex', + 'birth_date', + 'email', + 'phone', + 'toque_number' + ] + class EstablishmentEmployeeBackSerializer(serializers.ModelSerializer): """Establishment Employee serializer.""" diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index e751e4d4..deabd100 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -99,6 +99,9 @@ class EstablishmentTypeBaseSerializer(serializers.ModelSerializer): name_translated = TranslatedField() default_image_url = serializers.ImageField(source='default_image.image', allow_null=True) + preview_image = serializers.URLField(source='preview_image_url', + allow_null=True, + read_only=True) class Meta: """Meta class.""" @@ -110,6 +113,7 @@ class EstablishmentTypeBaseSerializer(serializers.ModelSerializer): 'use_subtypes', 'index_name', 'default_image_url', + 'preview_image', ] extra_kwargs = { 'name': {'write_only': True}, @@ -135,6 +139,9 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer): name_translated = TranslatedField() default_image_url = serializers.ImageField(source='default_image.image', allow_null=True) + preview_image = serializers.URLField(source='preview_image_url', + allow_null=True, + read_only=True) class Meta: """Meta class.""" @@ -146,6 +153,7 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer): 'establishment_type', 'index_name', 'default_image_url', + 'preview_image', ] extra_kwargs = { 'name': {'write_only': True}, diff --git a/apps/location/views/back.py b/apps/location/views/back.py index e306bc6e..4f29582d 100644 --- a/apps/location/views/back.py +++ b/apps/location/views/back.py @@ -7,6 +7,7 @@ from utils.permissions import IsCountryAdmin from utils.views import CreateDestroyGalleryViewMixin from rest_framework.permissions import IsAuthenticatedOrReadOnly from django.shortcuts import get_object_or_404 +from django.db import IntegrityError from utils.serializers import ImageBaseSerializer from location.filters import RegionFilter @@ -81,6 +82,15 @@ class CityGalleryCreateDestroyView(common.CityViewMixin, return gallery + def create(self, request, *args, **kwargs): + try: + return super(CityGalleryCreateDestroyView, self).create(request, *args, **kwargs) + except IntegrityError as e: + if not 'unique constraint' in e.args[0]: + raise e + models.CityGallery.objects.filter(city=kwargs['pk'], is_main=request.data['is_main']).delete() + return super(CityGalleryCreateDestroyView, self).create(request, *args, **kwargs) + class CityGalleryListView(common.CityViewMixin, generics.ListAPIView): diff --git a/apps/news/serializers.py b/apps/news/serializers.py index e3ffd01f..6a88bf08 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -121,6 +121,7 @@ class NewsListSerializer(NewsBaseSerializer): fields = NewsBaseSerializer.Meta.fields + ( 'image', + 'in_favorites', ) @@ -210,16 +211,23 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): """Overridden validate method.""" if 'descriptions' in attrs: descriptions = attrs.pop('descriptions') + locales = list(map(lambda x: x['locale'], descriptions)) status_to_bool = { 'active': True, 'inactive': False, } - attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions} - attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions} + attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions if 'slug' in obj} + attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions if 'title' in obj} attrs['locale_to_description_is_active'] = { obj['locale']: status_to_bool[obj['status']] for obj in descriptions } - attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions} + attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions if 'text' in obj} + if self.context['request'].method == 'PATCH': + instance = models.News.objects.get(pk=self.context['request'].data['id']) + for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']: + for locale in locales: + if not attrs[key].get(locale): + attrs[key][locale] = getattr(instance, key).get(locale) return attrs def create(self, validated_data): diff --git a/apps/product/serializers/common.py b/apps/product/serializers/common.py index 836d7c86..4eb79cec 100644 --- a/apps/product/serializers/common.py +++ b/apps/product/serializers/common.py @@ -36,6 +36,9 @@ class ProductSubTypeBaseSerializer(serializers.ModelSerializer): read_only=True) default_image_url = serializers.ImageField(source='default_image.image', allow_null=True) + preview_image = serializers.URLField(source='preview_image_url', + allow_null=True, + read_only=True) class Meta: model = models.ProductSubType @@ -44,6 +47,7 @@ class ProductSubTypeBaseSerializer(serializers.ModelSerializer): 'name_translated', 'index_name_display', 'default_image_url', + 'preview_image', ] @@ -52,6 +56,9 @@ class ProductTypeBaseSerializer(serializers.ModelSerializer): name_translated = TranslatedField() default_image_url = serializers.ImageField(source='default_image.image', allow_null=True) + preview_image = serializers.URLField(source='preview_image_url', + allow_null=True, + read_only=True) class Meta: model = models.ProductType @@ -60,6 +67,7 @@ class ProductTypeBaseSerializer(serializers.ModelSerializer): 'name_translated', 'index_name', 'default_image_url', + 'preview_image', ] diff --git a/apps/review/transfer_data.py b/apps/review/transfer_data.py index ac3749f6..db5dce42 100644 --- a/apps/review/transfer_data.py +++ b/apps/review/transfer_data.py @@ -55,7 +55,7 @@ def transfer_text_review(): text__isnull=True ).exclude( text__iexact='' - ).values('review_id', 'locale', 'text') + ).values('review_id', 'locale', 'text', 'updated_by', 'created_at', 'updated_at') serialized_data = ReviewTextSerializer(data=list(queryset), many=True) if serialized_data.is_valid(): @@ -142,5 +142,8 @@ data_types = { ], "product_review": [ transfer_product_reviews, + ], + "transfer_text_review": [ + transfer_text_review, ] } diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index e520932d..3c9dfc23 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -24,6 +24,7 @@ class EstablishmentDocument(Document): properties=OBJECT_FIELD_PROPERTIES), 'index_name': fields.KeywordField(attr='index_name'), 'default_image': fields.KeywordField(attr='default_image_url'), + 'preview_image_url': fields.KeywordField(), }) establishment_subtypes = fields.ObjectField( properties={ @@ -31,6 +32,7 @@ class EstablishmentDocument(Document): 'name': fields.ObjectField(attr='name_indexing'), 'index_name': fields.KeywordField(attr='index_name'), 'default_image': fields.KeywordField(attr='default_image_url'), + 'preview_image_url': fields.KeywordField(), }, multi=True) works_evening = fields.ListField(fields.IntegerField( diff --git a/apps/search_indexes/documents/product.py b/apps/search_indexes/documents/product.py index 3d6ebbd5..74034732 100644 --- a/apps/search_indexes/documents/product.py +++ b/apps/search_indexes/documents/product.py @@ -20,6 +20,7 @@ class ProductDocument(Document): 'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES), 'index_name': fields.KeywordField(), 'default_image': fields.KeywordField(attr='default_image_url'), + 'preview_image_url': fields.KeywordField(), }, ) subtypes = fields.ObjectField( @@ -28,6 +29,7 @@ class ProductDocument(Document): 'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES), 'index_name': fields.KeywordField(), 'default_image': fields.KeywordField(attr='default_image_url'), + 'preview_image_url': fields.KeywordField(), }, multi=True ) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 2a183c10..be0d517d 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -27,6 +27,8 @@ class EstablishmentTypeSerializer(serializers.Serializer): id = serializers.IntegerField() name_translated = serializers.SerializerMethodField() index_name = serializers.CharField() + default_image = serializers.CharField() + preview_image_url = serializers.CharField() def get_name_translated(self, obj): if isinstance(obj, dict): @@ -39,6 +41,8 @@ class ProductSubtypeDocumentSerializer(serializers.Serializer): id = serializers.IntegerField() name_translated = serializers.SerializerMethodField() + default_image = serializers.CharField() + preview_image_url = serializers.CharField() def get_name_translated(self, obj): if isinstance(obj, dict): @@ -102,6 +106,8 @@ class ProductTypeSerializer(serializers.Serializer): id = serializers.IntegerField() index_name = serializers.CharField() name_translated = serializers.SerializerMethodField() + default_image = serializers.CharField() + preview_image_url = serializers.CharField() @staticmethod def get_name_translated(obj): diff --git a/apps/search_indexes/views.py b/apps/search_indexes/views.py index e0735b2d..e59e2cf3 100644 --- a/apps/search_indexes/views.py +++ b/apps/search_indexes/views.py @@ -276,9 +276,6 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet): }, 'subtype': { 'field': 'establishment_subtypes.index_name', - 'lookups': [ - constants.LOOKUP_QUERY_IN, - ], }, 'works_noon': { 'field': 'works_noon', diff --git a/apps/transfer/management/commands/transfer.py b/apps/transfer/management/commands/transfer.py index 802f0989..7dc76d45 100644 --- a/apps/transfer/management/commands/transfer.py +++ b/apps/transfer/management/commands/transfer.py @@ -58,7 +58,8 @@ class Command(BaseCommand): 'setup_clean_db', 'languages', # №4 - перенос языков 'set_unused_regions', - 'update_fake_country_flag' + 'update_fake_country_flag', + 'transfer_text_review', # переводы для review с их авторами - запускать после overlook и product_review ] def handle(self, *args, **options): @@ -68,7 +69,8 @@ class Command(BaseCommand): if len(data_type) != 1: data_type = list(set(option for option in options.keys() if options[option]) & set(self.SHORT_DATA_TYPES)) if len(data_type) != 1: - print("You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n") + print( + "You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n") exit(1) else: data_type = data_type[0] diff --git a/apps/transfer/serializers/reviews.py b/apps/transfer/serializers/reviews.py index 6d3f50b4..7085ae6d 100644 --- a/apps/transfer/serializers/reviews.py +++ b/apps/transfer/serializers/reviews.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from review.models import Review +from review.models import Review, ReviewTextAuthor from account.models import User from translation.models import Language from establishment.models import Establishment @@ -97,24 +97,41 @@ class ReviewTextSerializer(serializers.Serializer): review_id = serializers.IntegerField() locale = serializers.CharField(allow_null=True) text = serializers.CharField() + updated_by = serializers.IntegerField(allow_null=True) + created_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S') + updated_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S') def validate(self, data): data.update({ 'new_text': self.get_text(data), 'review': self.get_review(data), + 'author': self.get_author(data), }) data.pop('review_id') - data.pop('locale') data.pop('text') return data def create(self, validated_data): review = validated_data['review'] + author_payload = { + 'review': review, + 'author': validated_data['author'], + 'locale': validated_data['locale'] or 'en-GB', + 'created': validated_data['created_at'], + } if review.text: review.text.update(validated_data['new_text']) else: review.text = validated_data['new_text'] review.save() + + if validated_data['author'] and validated_data['locale']: + review_author, _ = ReviewTextAuthor.objects.update_or_create( + review=review, + locale=author_payload['locale'], + defaults=author_payload, + ) + return review @staticmethod @@ -130,6 +147,12 @@ class ReviewTextSerializer(serializers.Serializer): raise ValueError(f"Review not found with old_id {data['review_id']}: ") return review + @staticmethod + def get_author(data): + user = User.objects.filter(old_id=data['updated_by']).first() + if user: + return user + class LanguageSerializer(serializers.ModelSerializer): LANGUAGES = { diff --git a/apps/utils/models.py b/apps/utils/models.py index ba3b924d..e3faed4e 100644 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -440,9 +440,11 @@ class HasTagsMixin(models.Model): @property def visible_tags(self): - return self.tags.filter(category__public=True).prefetch_related('category', - 'translation', 'category__translation')\ - .exclude(category__value_type='bool') + return self.tags.filter(category__public=True).prefetch_related( + 'category', + 'translation', + 'category__translation', + ).exclude(category__value_type='bool') class Meta: """Meta class.""" @@ -468,3 +470,8 @@ class TypeDefaultImageMixin: """Return image url.""" if hasattr(self, 'default_image') and self.default_image: return self.default_image.image.url + + @property + def preview_image_url(self): + if hasattr(self, 'default_image') and self.default_image: + return self.default_image.get_image_url(thumbnail_key='type_preview') diff --git a/project/settings/base.py b/project/settings/base.py index a7d3274f..93156f71 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -409,6 +409,7 @@ SORL_THUMBNAIL_ALIASES = { 'city_xlarge': {'geometry_string': '560x560', 'crop': 'center'}, 'city_detail': {'geometry_string': '1120x1120', 'crop': 'center'}, 'city_original': {'geometry_string': '2048x1536', 'crop': 'center'}, + 'type_preview': {'geometry_string': '300x260', 'crop': 'center'}, }