"""Tag serializers.""" from rest_framework import serializers from rest_framework.fields import SerializerMethodField from establishment.models import Establishment from establishment.models import EstablishmentType from news.models import News from news.models import NewsType from tag import models from utils.exceptions import BindingObjectNotFound from utils.exceptions import ObjectAlreadyAdded from utils.exceptions import RemovedBindingObjectNotFound from utils.serializers import TranslatedField class TagBaseSerializer(serializers.ModelSerializer): """Serializer for model Tag.""" def get_extra_kwargs(self): return super().get_extra_kwargs() label_translated = TranslatedField() index_name = serializers.CharField(source='value', read_only=True, allow_null=True) class Meta: """Meta class.""" model = models.Tag fields = ( 'id', 'label_translated', 'index_name', ) class TagBackOfficeSerializer(TagBaseSerializer): """Serializer for Tag model for Back office users.""" class Meta(TagBaseSerializer.Meta): """Meta class.""" fields = TagBaseSerializer.Meta.fields + ( 'label', 'category' ) class TagCategoryProductSerializer(serializers.ModelSerializer): """SHORT Serializer for TagCategory""" label_translated = TranslatedField() class Meta: """Meta class.""" model = models.TagCategory fields = ( 'id', 'label_translated', 'index_name', ) class TagCategoryBaseSerializer(serializers.ModelSerializer): """Serializer for model TagCategory.""" label_translated = TranslatedField() tags = SerializerMethodField() class Meta: """Meta class.""" model = models.TagCategory fields = ( 'id', 'label_translated', 'index_name', 'tags', ) def get_tags(self, obj): query_params = dict(self.context['request'].query_params) if len(query_params) > 1: return [] params = {} if 'establishment_type' in query_params: params = { 'establishments__isnull': False, } elif 'product_type' in query_params: params = { 'products__isnull': False, } tags = obj.tags.filter(**params).distinct() return TagBaseSerializer(instance=tags, many=True, read_only=True).data class FiltersTagCategoryBaseSerializer(serializers.ModelSerializer): """Serializer for model TagCategory.""" label_translated = TranslatedField() filters = SerializerMethodField() param_name = SerializerMethodField() type = SerializerMethodField() class Meta: """Meta class.""" model = models.TagCategory fields = ( 'id', 'label_translated', 'index_name', 'param_name', 'type', 'filters', ) def get_type(self, obj): return obj in ['open_now', ] def get_param_name(self, obj): return 'tags_id__in' def get_fields(self, *args, **kwargs): fields = super(FiltersTagCategoryBaseSerializer, self).get_fields() if self.get_type(self): fields.pop('filters', None) else: fields.pop('type', None) return fields def get_filters(self, obj): query_params = dict(self.context['request'].query_params) params = {} if 'establishment_type' in query_params: params = { 'establishments__isnull': False, } elif 'product_type' in query_params: params = { 'products__isnull': False, } tags = obj.tags.filter(**params).distinct() return TagBaseSerializer(instance=tags, many=True, read_only=True).data class TagCategoryShortSerializer(serializers.ModelSerializer): """Serializer for model TagCategory.""" label_translated = TranslatedField() value_type_display = serializers.CharField(source='get_value_type_display', read_only=True) class Meta(TagCategoryBaseSerializer.Meta): """Meta class.""" fields = [ 'label_translated', 'value_type_display', ] class TagCategoryBackOfficeDetailSerializer(TagCategoryBaseSerializer): """Tag Category detail serializer for back-office users.""" country_translated = TranslatedField(source='country.name_translated') class Meta(TagCategoryBaseSerializer.Meta): """Meta class.""" fields = TagCategoryBaseSerializer.Meta.fields + ( 'label', 'country', 'country_translated', ) class TagBindObjectSerializer(serializers.Serializer): """Serializer for binding tag category and objects""" ESTABLISHMENT = 'establishment' NEWS = 'news' TYPE_CHOICES = ( (ESTABLISHMENT, 'Establishment type'), (NEWS, 'News type'), ) type = serializers.ChoiceField(TYPE_CHOICES) object_id = serializers.IntegerField() def validate(self, attrs): view = self.context.get('view') request = self.context.get('request') obj_type = attrs.get('type') obj_id = attrs.get('object_id') tag = view.get_object() attrs['tag'] = tag if obj_type == self.ESTABLISHMENT: establishment = Establishment.objects.filter(pk=obj_id).first() if not establishment: raise BindingObjectNotFound() if request.method == 'POST' and tag.establishments.filter( pk=establishment.pk).exists(): raise ObjectAlreadyAdded() if request.method == 'DELETE' and not tag.establishments.filter( pk=establishment.pk).exists(): raise RemovedBindingObjectNotFound() attrs['related_object'] = establishment elif obj_type == self.NEWS: news = News.objects.filter(pk=obj_id).first() if not news: raise BindingObjectNotFound() if request.method == 'POST' and tag.news.filter(pk=news.pk).exists(): raise ObjectAlreadyAdded() if request.method == 'DELETE' and not tag.news.filter( pk=news.pk).exists(): raise RemovedBindingObjectNotFound() attrs['related_object'] = news return attrs class TagCategoryBindObjectSerializer(serializers.Serializer): """Serializer for binding tag category and objects""" ESTABLISHMENT_TYPE = 'establishment_type' NEWS_TYPE = 'news_type' TYPE_CHOICES = ( (ESTABLISHMENT_TYPE, 'Establishment type'), (NEWS_TYPE, 'News type'), ) type = serializers.ChoiceField(TYPE_CHOICES) object_id = serializers.IntegerField() def validate(self, attrs): view = self.context.get('view') request = self.context.get('request') obj_type = attrs.get('type') obj_id = attrs.get('object_id') tag_category = view.get_object() attrs['tag_category'] = tag_category if obj_type == self.ESTABLISHMENT_TYPE: establishment_type = EstablishmentType.objects.filter(pk=obj_id). \ first() if not establishment_type: raise BindingObjectNotFound() if request.method == 'POST' and tag_category.establishment_types. \ filter(pk=establishment_type.pk).exists(): raise ObjectAlreadyAdded() if request.method == 'DELETE' and not tag_category. \ establishment_types.filter(pk=establishment_type.pk). \ exists(): raise RemovedBindingObjectNotFound() attrs['related_object'] = establishment_type elif obj_type == self.NEWS_TYPE: news_type = NewsType.objects.filter(pk=obj_id).first() if not news_type: raise BindingObjectNotFound() if request.method == 'POST' and tag_category.news_types. \ filter(pk=news_type.pk).exists(): raise ObjectAlreadyAdded() if request.method == 'DELETE' and not tag_category.news_types. \ filter(pk=news_type.pk).exists(): raise RemovedBindingObjectNotFound() attrs['related_object'] = news_type return attrs