gault-millau/apps/transfer/serializers/guide.py
2019-12-26 10:24:08 +03:00

360 lines
15 KiB
Python

from itertools import chain
import yaml
from django.utils.text import slugify
from pycountry import countries, subdivisions
from rest_framework import serializers
from collection import models
from establishment.models import EstablishmentType
from location.models import Country, Region, WineRegion
from main.models import SiteSettings
from review.models import Review
from transfer.mixins import TransferSerializerMixin
from translation.models import Language
class GuideSerializer(TransferSerializerMixin):
id = serializers.IntegerField()
title = serializers.CharField()
vintage = serializers.IntegerField()
slug = serializers.CharField()
state = serializers.CharField()
site_id = serializers.IntegerField()
inserter_field = serializers.CharField()
class Meta:
model = models.Guide
fields = (
'id',
'title',
'vintage',
'slug',
'state',
'site_id',
'inserter_field',
)
def validate(self, attrs):
"""Overridden validate method."""
attrs['old_id'] = attrs.pop('id')
attrs['name'] = attrs.pop('title')
attrs['vintage'] = int(attrs.pop('vintage'))
attrs['state'] = self.get_state(attrs.pop('state'))
attrs['site'] = self.get_site(attrs.pop('site_id'))
attrs['guide_type'] = self.get_guide_type(attrs.pop('inserter_field'))
return attrs
def get_state(self, state: str):
if state == 'built':
return models.Guide.BUILT
elif state == 'removing':
return models.Guide.REMOVING
elif state == 'building':
return models.Guide.BUILDING
else:
return models.Guide.WAITING
def get_site(self, site_id):
qs = SiteSettings.objects.filter(old_id=site_id)
if qs.exists():
return qs.first()
def get_guide_type(self, inserter_field):
if inserter_field:
if inserter_field.startswith('restaurant'):
return models.Guide.RESTAURANT
elif inserter_field.startswith('wine'):
return models.Guide.WINE
class GuideFilterSerializer(TransferSerializerMixin):
id = serializers.IntegerField()
year = serializers.CharField(allow_null=True)
establishment_type = serializers.CharField(allow_null=True)
countries = serializers.CharField(allow_null=True)
regions = serializers.CharField(allow_null=True)
subregions = serializers.CharField(allow_null=True)
wine_regions = serializers.CharField(allow_null=True)
locales = serializers.CharField(allow_null=True)
states = serializers.CharField(allow_null=True)
max_mark = serializers.FloatField(allow_null=True)
min_mark = serializers.FloatField(allow_null=True)
marks_only = serializers.NullBooleanField()
guide_id = serializers.IntegerField()
class Meta:
model = models.GuideFilter
fields = (
'id',
'year',
'establishment_type',
'countries',
'regions',
'subregions',
'wine_regions',
'max_mark',
'min_mark',
'marks_only',
'locales',
'states',
'guide_id',
)
def create(self, validated_data):
qs = self.Meta.model.objects.filter(guide=validated_data.get('guide'))
if not qs.exists():
return super().create(validated_data)
@staticmethod
def parse_ruby_helper(raw_value: str):
"""Parse RubyActiveSupport records"""
def convert_entry(loader, node):
return {e[0]: e[1] for e in loader.construct_pairs(node)}
loader = yaml.Loader
loader.add_constructor('!ruby/hash:ActiveSupport::HashWithIndifferentAccess', convert_entry)
return yaml.load(raw_value, Loader=loader) if raw_value else None
@staticmethod
def parse_dictionary(dictionary: dict):
"""
Exclude root values from dictionary.
Convert {key_2: [value_1, value_2]} into
[value_1, value_2]
"""
return list(chain.from_iterable(dictionary.values()))
@staticmethod
def parse_nested_dictionary(dictionary: dict):
"""
Exclude root values from dictionary.
Convert {key_1: {key_2: [value_1, value_2]}} into
[value_1, value_2]
"""
l = []
for i in dictionary:
l.append(list(chain.from_iterable(list(dictionary[i].values()))))
return list(chain.from_iterable(l))
def get_country(self, code_alpha_3: str) -> Country:
country = countries.get(alpha_3=code_alpha_3.upper())
if country:
country_name = country.name
country_code = country.alpha_2
if country_name and country_code:
country, _ = Country.objects.get_or_create(
code__icontains=country_code,
name__contains={'en-GB': country_name},
defaults={
'code': country_code,
'name': {'en-GB': country_name}
}
)
return country
def get_region(self, region_code_alpha_3: str,
country_code_alpha_3: str,
sub_region_code_alpha_3: str = None):
country = self.get_country(country_code_alpha_3)
if country:
country_code_alpha_2 = country.code.upper()
region_qs = Region.objects.filter(code__iexact=region_code_alpha_3,
country__code__iexact=country_code_alpha_2)
if region_qs.exists():
return region_qs.first()
# If region isn't existed, check sub region for parent_code (region code)
if sub_region_code_alpha_3:
# sub region
subdivision = subdivisions.get(
code=f"{country_code_alpha_2}-{sub_region_code_alpha_3}")
if subdivision:
# try with parent code
subdivision_region = subdivisions.get(code=subdivision.__dict__.get('_fields')
.get('parent_code'))
if not subdivision_region:
# try with parent
subdivision_region = subdivisions.get(code=subdivision.__dict__.get('_fields')
.get('parent'))
if subdivision_region:
obj = Region.objects.create(
name=subdivision_region.name,
code=subdivision_region.code,
country=country)
return obj
def validate_year(self, value):
return self.parse_ruby_helper(value)
def validate_establishment_type(self, value):
return self.parse_ruby_helper(value)
def validate_countries(self, value):
return self.parse_ruby_helper(value)
def validate_regions(self, value):
return self.parse_ruby_helper(value)
def validate_subregions(self, value):
return self.parse_ruby_helper(value)
def validate_wine_regions(self, value):
return self.parse_ruby_helper(value)
def validate_wine_classifications(self, value):
return self.parse_ruby_helper(value)
def validate_wine_colors(self, value):
return self.parse_ruby_helper(value)
def validate_wine_types(self, value):
return self.parse_ruby_helper(value)
def validate_locales(self, value):
return self.parse_ruby_helper(value)
def validate_states(self, value):
return self.parse_ruby_helper(value)
def validate(self, attrs):
sub_regions = attrs.pop('subregions')
regions = attrs.pop('regions')
attrs['old_id'] = attrs.pop('id')
attrs['review_vintage_json'] = self.get_review_vintage(attrs.pop('year'))
attrs['establishment_type_json'] = self.get_establishment_type_ids(
attrs.pop('establishment_type'))
attrs['country_json'] = self.get_country_ids(attrs.pop('countries'))
attrs['region_json'] = self.get_region_ids(regions=regions,
sub_regions=sub_regions)
attrs['sub_region_json'] = self.get_sub_region_ids(sub_regions)
attrs['wine_region_json'] = self.get_wine_region_ids(attrs.pop('wine_regions'))
attrs['with_mark'] = attrs.pop('marks_only') or True
attrs['locale_json'] = self.get_locale_ids(attrs.pop('locales'))
attrs['review_state_json'] = self.get_review_state(attrs.pop('states'))
attrs['guide'] = self.get_guide(attrs.pop('guide_id'))
return attrs
def get_review_vintage(self, year):
if hasattr(year, '__iter__'):
return {'vintage': list(set(int(i) for i in set(year) if i.isdigit()))}
return {'vintage': [year, ]}
def get_establishment_type_ids(self, establishment_types):
establishment_type_ids = []
if establishment_types:
for establishment_type in establishment_types:
establishment_type_qs = EstablishmentType.objects.filter(index_name__iexact=establishment_type)
if not establishment_type_qs.exists():
obj = EstablishmentType.objects.create(
name={'en-GB': establishment_type.capitalize()},
index_name=slugify(establishment_type))
else:
obj = establishment_type_qs.first()
establishment_type_ids.append(obj.id)
return {'id': list(set(establishment_type_ids))}
def get_country_ids(self, country_codes_alpha_3):
country_ids = []
if country_codes_alpha_3:
for code_alpha_3 in country_codes_alpha_3:
# Code can be an empty string.
if code_alpha_3 and not code_alpha_3 == 'AAA':
country = self.get_country(code_alpha_3)
if not country:
raise serializers.ValidationError({'detail': f'Country with alpha code 3 -'
f'{code_alpha_3}, is not found.'})
country_ids.append(country.id)
return {'id': list(set(country_ids))}
def get_region_ids(self, regions, sub_regions):
region_ids = []
if regions:
for country_code_alpha_3 in regions:
for region_code_alpha_3 in regions[country_code_alpha_3]:
# Get region from sub region code.
if sub_regions and country_code_alpha_3 in sub_regions:
if region_code_alpha_3 in sub_regions[country_code_alpha_3]:
for sub_region_code_alpha_3 in sub_regions[country_code_alpha_3][region_code_alpha_3]:
region = self.get_region(
region_code_alpha_3=region_code_alpha_3,
country_code_alpha_3=country_code_alpha_3,
sub_region_code_alpha_3=sub_region_code_alpha_3)
if region:
region_ids.append(region.id)
return {'id': list(set(region_ids))}
def get_sub_region_ids(self, sub_regions):
sub_region_ids = []
if sub_regions:
for country_code_alpha_3 in sub_regions:
# FRA etc.
if country_code_alpha_3 in sub_regions:
for region_code_alpha_3 in sub_regions[country_code_alpha_3]:
# B, C, A etc.
if region_code_alpha_3 in sub_regions[country_code_alpha_3]:
for sub_region_code_alpha_3 in sub_regions[country_code_alpha_3][region_code_alpha_3]:
# 24, 32 etc.
# Get parent region
region = self.get_region(
region_code_alpha_3=region_code_alpha_3,
country_code_alpha_3=country_code_alpha_3,
sub_region_code_alpha_3=sub_region_code_alpha_3)
if region:
sub_region_qs = Region.objects.filter(parent_region__code=region.code)
if sub_region_qs.exists():
sub_region_ids.append(sub_region_qs.first().id)
else:
subdivision = subdivisions.get(code=region.code.upper())
if subdivision:
sub_region, _ = Region.objects.get_or_create(
name=subdivision.name,
code=subdivision.code,
parent_region=region,
country=region.country)
sub_region_ids.append(sub_region.id)
return {'id': list(set(sub_region_ids))}
def get_wine_region_ids(self, wine_regions):
wine_region_ids = []
if wine_regions:
for wine_region in wine_regions:
qs = WineRegion.objects.filter(name__iexact=wine_region)
if not qs.exists():
raise serializers.ValidationError({
'detail': f'Wine region - {wine_region}, is not found.'})
wine_region_ids.append(qs.first().id)
return {'id': list(set(wine_region_ids))}
def get_locale_ids(self, locales):
locale_ids = []
if locales:
for locale in [locale for locale in locales if locale]:
if len(locale) == 2:
qs = Language.objects.filter(locale__startswith=locale)
else:
qs = Language.objects.filter(locale=locale)
if not qs.exists():
raise serializers.ValidationError({
'detail': f'Language with locale - {locale}, is not found.'})
locale_ids.extend(qs.values_list('id', flat=True))
return {'id': list(set(locale_ids))}
def get_review_state(self, states):
review_states = []
if states:
for state in [state for state in states if state]:
if state == 'published':
review_states.append(Review.READY)
else:
review_states.append(Review.TO_INVESTIGATE)
return {'state': list(set(review_states))}
def get_guide(self, old_guide_id: int):
qs = models.Guide.objects.filter(old_id=old_guide_id)
if qs.exists():
return qs.first()