from django.shortcuts import get_object_or_404 from rest_framework import serializers from rest_framework_recursive.fields import RecursiveField from slugify import slugify from collection import models from establishment.serializers import EstablishmentGuideElementSerializer from location import models as location_models from main.serializers import SiteShortSerializer from product.serializers import ProductGuideElementSerializer from utils import exceptions from utils.methods import string_random from utils.serializers import TranslatedField class CollectionBaseSerializer(serializers.ModelSerializer): """Collection base serializer""" name_translated = TranslatedField() description_translated = TranslatedField() class Meta: model = models.Collection fields = [ 'id', 'name_translated', 'description_translated', 'image_url', 'slug', ] class CollectionSerializer(CollectionBaseSerializer): """Collection serializer""" # COMMON block_size = serializers.JSONField() is_publish = serializers.BooleanField() on_top = serializers.BooleanField() slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) # REQUEST start = serializers.DateTimeField(write_only=True) end = serializers.DateTimeField(write_only=True) country = serializers.PrimaryKeyRelatedField( queryset=location_models.Country.objects.all(), write_only=True) class Meta(CollectionBaseSerializer.Meta): fields = CollectionBaseSerializer.Meta.fields + [ 'start', 'end', 'is_publish', 'on_top', 'country', 'block_size', ] class GuideFilterBaseSerializer(serializers.ModelSerializer): """GuideFilter serializer""" class Meta: """Meta class.""" model = models.GuideFilter fields = [ 'id', 'establishment_type_json', 'country_json', 'region_json', 'sub_region_json', 'wine_region_json', 'with_mark', 'locale_json', 'max_mark', 'min_mark', 'review_vintage_json', 'review_state_json', 'guide', ] extra_kwargs = { 'guide': {'write_only': True, 'required': False}, 'max_mark': {'required': True}, 'min_mark': {'required': True}, } @property def request_kwargs(self): """Get url kwargs from request.""" return self.context.get('request').parser_context.get('kwargs') def create(self, validated_data): """Overridden create method.""" guide = get_object_or_404(models.Guide.objects.all(), pk=self.request_kwargs.get('pk')) validated_data['guide'] = guide guide_filter = super().create(validated_data) guide.generate_elements() return guide_filter class GuideBaseSerializer(serializers.ModelSerializer): """Guide serializer""" state_display = serializers.CharField(source='get_state_display', read_only=True) guide_type_display = serializers.CharField(read_only=True) site_detail = SiteShortSerializer(read_only=True, source='site') guide_filters = GuideFilterBaseSerializer(read_only=True, source='guidefilter') # counters # restaurant_counter = serializers.IntegerField(read_only=True) # shop_counter = serializers.IntegerField(read_only=True) # wine_counter = serializers.IntegerField(read_only=True) # present_objects_counter = serializers.IntegerField(read_only=True) count_objects_during_init = serializers.IntegerField(read_only=True, source='count_related_objects') class Meta: model = models.Guide fields = [ 'id', 'name', 'start', 'end', 'vintage', 'slug', 'guide_type', 'guide_type_display', 'site', 'site_detail', 'state', 'state_display', 'guide_filters', # 'restaurant_counter', # 'shop_counter', # 'wine_counter', # 'present_objects_counter', 'count_objects_during_init', ] extra_kwargs = { 'guide_type': {'write_only': True, 'required': True}, 'site': {'write_only': True, 'required': True}, 'state': {'write_only': True}, 'start': {'required': True}, 'slug': {'required': False}, 'count_objects_during_init': {'read_only': True}, 'vintage': {'required': True}, } def create(self, validated_data): """Overridden create method.""" slug = validated_data.get('slug') name = validated_data.get('name') vintage = validated_data.get('vintage') if not slug: slug = slugify(f'{name} {vintage}', word_boundary=True) while models.Guide.objects.filter(slug=slug).exists(): slug = slugify(f'{name} {vintage} {string_random()}', word_boundary=True) validated_data['slug'] = slug return super(GuideBaseSerializer, self).create(validated_data) class GuideShortSerializer(serializers.ModelSerializer): """Serializer for model Guide.""" class Meta(GuideBaseSerializer.Meta): """Meta-class.""" fields = [ 'id', 'name', ] class GuideElementBaseSerializer(serializers.ModelSerializer): """Serializer for model GuideElement.""" establishment_detail = EstablishmentGuideElementSerializer(read_only=True, source='establishment') section_name = serializers.CharField(source='section.name', allow_null=True) wine_color_section_name = serializers.CharField(source='wine_color_section.name', allow_null=True) wine_region_name = serializers.CharField(source='wine_region.name', allow_null=True) node_name = serializers.CharField(source='guide_element_type.name') label_photo = serializers.ImageField(source='label_photo.image', allow_null=True) city_name = serializers.CharField(source='city.name', allow_null=True) product_detail = ProductGuideElementSerializer(read_only=True, source='product') children = RecursiveField(required=False, many=True, source='get_children') class Meta: """Meta class.""" model = models.GuideElement fields = [ 'id', 'node_name', 'establishment_detail', 'review', 'product_detail', 'priority', 'city_name', 'section_name', 'wine_color_section_name', 'wine_region_name', 'children', 'label_photo', ] class AdvertorialBaseSerializer(serializers.ModelSerializer): """Serializer for model Advertorial.""" class Meta: """Meta class.""" model = models.Advertorial fields = [ 'number_of_pages', 'right_pages', 'guide_element', ] extra_kwargs = { 'guide_element': {'required': False} } @property def request_kwargs(self): return self.context.get('request').parser_context.get('kwargs') def validate(self, attrs): # check existence in guide guide = get_object_or_404(models.Guide.objects.all(), pk=self.request_kwargs.get('pk')) root_node = models.GuideElement.objects.get_root_node(guide) guide_element_qs = root_node.get_descendants().filter(pk=self.request_kwargs.get('element_pk')) guide_element = guide_element_qs.first() if not guide_element_qs.exists(): raise exceptions.GuideElementError() if models.Advertorial.objects.filter(guide_element=guide_element).exists(): raise exceptions.AdvertorialError() attrs['guide_element'] = guide_element return attrs class GuideElementExportSerializer(GuideElementBaseSerializer): """GuideElement export serializer.""" # ESTABLISHMENT name = serializers.CharField(source='establishment.name', default=None) public_mark = serializers.CharField(source='establishment.public_mark_display', default=None) toque_number = serializers.IntegerField(source='establishment.toque_number', default=None) schedule = serializers.DictField(source='establishment.schedule_display', default=None) address = serializers.CharField(source='establishment.address.full_address', default=None) phones = serializers.ListField(source='establishment.contact_phones', default=None) establishment_type = serializers.CharField(source='establishment.establishment_type.label', default=None) establishment_subtypes = serializers.ListField(source='establishment.establishment_subtype_labels', default=None) review = serializers.DictField(source='establishment.last_published_review_data', default=None) price_level = serializers.CharField(source='establishment.price_level_display', default=None) metadata = serializers.ListField(source='establishment.metadata', default=None) advertorial = serializers.DictField(source='advertorial.__dict__', default=None) # PRODUCT product_name = serializers.CharField(source='product.name', default=None) product_review = serializers.DictField(source='product.last_published_review_data', default=None) product_type = serializers.CharField(source='product.product_type.label', default=None) product_subtypes = serializers.CharField(source='product.product_subtype_labels', default=None) product_city = serializers.CharField(source='product.establishment.address.city.name', default=None) product_address = serializers.CharField(source='product.establishment.address.full_address', default=None) product_metadata = serializers.ListField(source='product.metadata', default=None) class Meta: model = models.GuideElement fields = [ 'id', 'guide', 'node_name', 'city_name', 'wine_color_section_name', 'name', 'public_mark', 'toque_number', 'schedule', 'address', 'phones', 'establishment_type', 'establishment_subtypes', 'review', 'price_level', 'metadata', 'advertorial', 'product_name', 'product_review', 'product_type', 'product_subtypes', 'product_address', 'product_city', 'product_metadata', ]