diff --git a/apps/establishment/models.py b/apps/establishment/models.py index e3384dfb..4ab2fe24 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -13,8 +13,9 @@ from phonenumber_field.modelfields import PhoneNumberField from location.models import Address from collection.models import Collection +from main.models import MetaDataContent from review.models import Review -from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, URLImageMixin, +from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, TranslatedFieldsMixin, BaseAttributes) @@ -70,6 +71,20 @@ class EstablishmentSubType(ProjectBaseMixin, TranslatedFieldsMixin): class EstablishmentQuerySet(models.QuerySet): """Extended queryset for Establishment model.""" + def with_base_related(self): + """Return qs with related objects.""" + return self.select_related('address').prefetch_related( + models.Prefetch('tags', + MetaDataContent.objects.select_related( + 'metadata__category')) + ) + + def with_extended_related(self): + return self.select_related('establishment_type').\ + prefetch_related('establishment_subtypes', 'awards', 'schedule', + 'phones').\ + prefetch_actual_employees() + def search(self, value, locale=None): """Search text in JSON fields.""" if locale is not None: @@ -228,7 +243,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin): name = models.CharField(_('name'), max_length=255, default='') name_translated = models.CharField(_('Transliterated name'), - max_length=255, default='') + max_length=255, default='') description = TJSONField(blank=True, null=True, default=None, verbose_name=_('description'), help_text='{"en-GB":"some text"}') @@ -312,12 +327,12 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin): 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) + # @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 diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 7013fe6a..17d5f1d5 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,12 +1,9 @@ -import json from rest_framework import serializers - from establishment import models -from timetable.models import Timetable from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, - ContactPhonesSerializer, SocialNetworkRelatedSerializers, EstablishmentDetailSerializer -) + ContactPhonesSerializer, SocialNetworkRelatedSerializers, + EstablishmentTypeSerializer) from main.models import Currency @@ -21,6 +18,7 @@ class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): emails = ContactEmailsSerializer(read_only=True, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=True, many=True, ) slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) + type = EstablishmentTypeSerializer(source='establishment_type') class Meta: model = models.Establishment @@ -52,6 +50,7 @@ class EstablishmentRUDSerializer(EstablishmentBaseSerializer): phones = ContactPhonesSerializer(read_only=False, many=True, ) emails = ContactEmailsSerializer(read_only=False, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=False, many=True, ) + type = EstablishmentTypeSerializer(source='establishment_type') class Meta: model = models.Establishment diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 7b974887..f1b2d5ed 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -1,17 +1,17 @@ """Establishment serializers.""" from rest_framework import serializers - +from django.utils.translation import gettext_lazy as _ from comment import models as comment_models from comment.serializers import common as comment_serializers from establishment import models from favorites.models import Favorites -from location.serializers import AddressSerializer +from location.serializers import AddressSimpleSerializer from main.models import MetaDataContent from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer from review import models as review_models from timetable.serialziers import ScheduleRUDSerializer from utils import exceptions as utils_exceptions -from django.utils.translation import gettext_lazy as _ +from utils.serializers import TranslatedField class ContactPhonesSerializer(serializers.ModelSerializer): @@ -142,11 +142,11 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer): class EstablishmentBaseSerializer(serializers.ModelSerializer): """Base serializer for Establishment model.""" - type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) - subtypes = EstablishmentSubTypeSerializer(many=True) - address = AddressSerializer() - tags = MetaDataContentSerializer(many=True) + + preview_image = serializers.URLField(source='preview_image_url') slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) + address = AddressSimpleSerializer() + tags = MetaDataContentSerializer(many=True) class Meta: """Meta class.""" @@ -159,60 +159,53 @@ class EstablishmentBaseSerializer(serializers.ModelSerializer): 'price_level', 'toque_number', 'public_mark', - 'type', - 'subtypes', + 'slug', + 'preview_image', + 'in_favorites', 'address', 'tags', - 'slug', ] class EstablishmentListSerializer(EstablishmentBaseSerializer): """Serializer for Establishment model.""" - # Annotated fields + in_favorites = serializers.BooleanField(allow_null=True) - preview_image = serializers.URLField(source='preview_image_url') - - class Meta: + class Meta(EstablishmentBaseSerializer.Meta): """Meta class.""" - model = models.Establishment fields = EstablishmentBaseSerializer.Meta.fields + [ 'in_favorites', - 'preview_image', ] class EstablishmentDetailSerializer(EstablishmentListSerializer): """Serializer for Establishment model.""" - description_translated = serializers.CharField(allow_null=True) + + description_translated = TranslatedField() + image = serializers.URLField(source='image_url') + type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) + subtypes = EstablishmentSubTypeSerializer(many=True, source='establishment_subtypes') awards = AwardSerializer(many=True) schedule = ScheduleRUDSerializer(many=True, allow_null=True) - phones = ContactPhonesSerializer(read_only=True, many=True, ) - emails = ContactEmailsSerializer(read_only=True, many=True, ) + phones = ContactPhonesSerializer(read_only=True, many=True) + emails = ContactEmailsSerializer(read_only=True, many=True) review = serializers.SerializerMethodField() employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees', many=True) menu = MenuSerializers(source='menu_set', many=True, read_only=True) - best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) - slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) - - in_favorites = serializers.SerializerMethodField() - - image = serializers.URLField(source='image_url') - - class Meta: + class Meta(EstablishmentListSerializer.Meta): """Meta class.""" - model = models.Establishment fields = EstablishmentListSerializer.Meta.fields + [ 'description_translated', - 'price_level', 'image', + 'subtypes', + 'type', 'awards', 'schedule', 'website', @@ -228,23 +221,23 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer): 'best_price_menu', 'best_price_carte', 'transportation', - 'slug', ] + # todo: refactor this s (make as prefetch to model as attr or make as model property) def get_review(self, obj): """Serializer method for getting last published review""" return ReviewSerializer(obj.reviews.by_status(status=review_models.Review.READY) .order_by('-published_at').first()).data - def get_in_favorites(self, obj): - """Get in_favorites status flag""" - user = self.context.get('request').user - if user.is_authenticated: - return obj.id in user.favorites.by_content_type(app_label='establishment', - model='establishment')\ - .values_list('object_id', flat=True) - else: - return False + # def get_in_favorites(self, obj): + # """Get in_favorites status flag""" + # user = self.context.get('request').user + # if user.is_authenticated: + # return obj.id in user.favorites.by_content_type(app_label='establishment', + # model='establishment')\ + # .values_list('object_id', flat=True) + # else: + # return False class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer): diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 974fca8a..78526bdd 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -4,10 +4,17 @@ from rest_framework import generics from establishment import models from establishment import serializers -from establishment.views.common import EstablishmentMixin -class EstablishmentListCreateView(EstablishmentMixin, generics.ListCreateAPIView): +class EstablishmentMixinViews: + """Establishment mixin.""" + + def get_queryset(self): + """Overrided method 'get_queryset'.""" + return models.Establishment.objects.published().with_related() + + +class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAPIView): """Establishment list/create view.""" queryset = models.Establishment.objects.all() serializer_class = serializers.EstablishmentListCreateSerializer diff --git a/apps/establishment/views/common.py b/apps/establishment/views/common.py index b57d6ef6..3029c080 100644 --- a/apps/establishment/views/common.py +++ b/apps/establishment/views/common.py @@ -1,16 +1 @@ """Establishment app views.""" - -from rest_framework import permissions - -from establishment import models - - -class EstablishmentMixin: - """Establishment mixin.""" - - permission_classes = (permissions.AllowAny,) - - def get_queryset(self): - """Overrided method 'get_queryset'.""" - return models.Establishment.objects.published() \ - .prefetch_actual_employees() diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index ce2bed05..3748b95f 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -1,27 +1,47 @@ """Establishment app views.""" - from django.contrib.gis.geos import Point from django.shortcuts import get_object_or_404 from rest_framework import generics, permissions from comment import models as comment_models -from establishment import filters -from establishment import models, serializers -from establishment.views import EstablishmentMixin +from establishment import filters, models, serializers from main.models import MetaDataContent from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer -class EstablishmentListView(EstablishmentMixin, generics.ListAPIView): +class EstablishmentMixinView: + """Establishment mixin.""" + + permission_classes = (permissions.AllowAny,) + + def get_queryset(self): + """Overrided method 'get_queryset'.""" + return models.Establishment.objects.published().with_base_related().\ + annotate_in_favorites(self.request.user) + + +class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView): """Resource for getting a list of establishments.""" - serializer_class = serializers.EstablishmentListSerializer + filter_class = filters.EstablishmentFilter + serializer_class = serializers.EstablishmentListSerializer def get_queryset(self): """Overridden method 'get_queryset'.""" qs = super(EstablishmentListView, self).get_queryset() - return qs.by_country_code(code=self.request.country_code) \ - .annotate_in_favorites(user=self.request.user) + if self.request.country_code: + qs = qs.by_country_code(self.request.country_code) + return qs + + +class EstablishmentRetrieveView(EstablishmentMixinView, generics.RetrieveAPIView): + """Resource for getting a establishment.""" + + lookup_field = 'slug' + serializer_class = serializers.EstablishmentDetailSerializer + + def get_queryset(self): + return super().get_queryset().with_extended_related() class EstablishmentSimilarListView(EstablishmentListView): @@ -33,11 +53,6 @@ class EstablishmentSimilarListView(EstablishmentListView): return super().get_queryset().similar(establishment_slug=self.kwargs.get('slug'))\ .order_by('-total_mark')[:13] -class EstablishmentRetrieveView(EstablishmentMixin, generics.RetrieveAPIView): - """Resource for getting a establishment.""" - lookup_field = 'slug' - serializer_class = serializers.EstablishmentDetailSerializer - class EstablishmentTypeListView(generics.ListAPIView): """Resource for getting a list of establishment types.""" diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 555cf499..1dee92ed 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -1,7 +1,6 @@ """Location app common serializers.""" from django.contrib.gis.geos import Point from rest_framework import serializers - from location import models from utils.serializers import TranslatedField @@ -86,6 +85,7 @@ class CitySerializer(serializers.ModelSerializer): class AddressSerializer(serializers.ModelSerializer): """Address serializer.""" + city_id = serializers.PrimaryKeyRelatedField( source='city', queryset=models.City.objects.all()) @@ -128,3 +128,18 @@ class AddressSerializer(serializers.ModelSerializer): setattr(instance, 'geo_lon', float(0)) return super().to_representation(instance) + +class AddressSimpleSerializer(serializers.ModelSerializer): + """Serializer for address obj in related objects.""" + + class Meta: + """Meta class.""" + + model = models.Address + fields = ( + 'id', + 'street_name_1', + 'street_name_2', + 'number', + 'postal_code', + )