From 6645b590b87aa944510bc2cad730b1b1a9486148 Mon Sep 17 00:00:00 2001 From: Dmitry Borzenin Date: Fri, 7 Feb 2020 15:52:25 +0300 Subject: [PATCH 1/5] Add Parser for News slug --- apps/utils/parsers.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 apps/utils/parsers.py diff --git a/apps/utils/parsers.py b/apps/utils/parsers.py new file mode 100644 index 00000000..30ed754e --- /dev/null +++ b/apps/utils/parsers.py @@ -0,0 +1,43 @@ + + +class NewsSlug: + def __init__(self, value=None, locale=None, count=0): + self.value = value + self.locale = locale + self.count = count + + @classmethod + def parse(cls, raw_slug, country_codes): + slug, *rest = raw_slug.split('-') + instance = NewsSlug() + + if len(rest) >= 1 and rest[-1] in country_codes: + instance.value = '-'.join([slug, *rest[:-1]]) + instance.locale = rest[-1] + elif len(rest) >= 2 and rest[-1].isdigit() and rest[-2] in country_codes: + instance.value = '-'.join([slug, *rest[:-2]]) + instance.locale = rest[-2] + instance.count = int(rest[-1]) + else: + instance.value = '-'.join([slug, *rest]) + + return instance + + def __lt__(self, other): + return self.value < other.value + + def __str__(self): + if self.value is None: + raise ValueError('No value for slug') + + slug_parts = [self.value] + if self.locale is not None: + slug_parts.append(self.locale) + + if self.count != 0: + slug_parts.append(str(self.count)) + + return '-'.join(slug_parts) + + def __repr__(self): + return f'<{self.__class__.__name__} {self.value}, {self.locale}, {self.count}>' From 2fa6df0af84a4d50f307cf62482ef57e18a13550 Mon Sep 17 00:00:00 2001 From: Dmitry Borzenin Date: Fri, 7 Feb 2020 15:56:18 +0300 Subject: [PATCH 2/5] Fix news duplicate creation (unique slugs) --- apps/news/models.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/news/models.py b/apps/news/models.py index e840f9c5..da860c50 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -24,6 +24,8 @@ from utils.models import ( TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin, ) from utils.querysets import TranslationQuerysetMixin +from location.models import Country +from utils.parsers import NewsSlug class Agenda(ProjectBaseMixin, TranslatedFieldsMixin): @@ -358,9 +360,28 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, return f'news: {next(iter(self.slugs.values()))}' def create_duplicate(self, new_country, view_count_model): + country_codes = list(Country.objects.all().values_list('code', flat=True)) + all_slugs = {slug_value + for slug_dict in News.objects.all().values_list('slugs', flat=True) + for slug_value in slug_dict.values()} + + new_slugs = {} + for locale, raw_slug in self.slugs.items(): + slug = NewsSlug.parse(raw_slug, country_codes) + similar_slugs = sorted(x for x in all_slugs if NewsSlug.parse(x, country_codes).value == slug.value) + if len(similar_slugs) == 0: + new_slugs[locale] = NewsSlug(slug.value, new_country.code) + else: + last_slug = NewsSlug.parse(similar_slugs[-1], country_codes) + new_slug = NewsSlug(slug.value, new_country.code, last_slug.count) + if last_slug.locale is not None: + new_slug.count += 1 + + new_slugs[locale] = str(new_slug) + self.pk = None self.state = self.UNPUBLISHED - self.slugs = {locale: f'{slug}-{new_country.code}' for locale, slug in self.slugs.items()} + self.slugs = new_slugs self.country = new_country self.views_count = view_count_model self.duplication_date = timezone.now() From 73a5f9dc0937bd9312d864e799f97e4c17699cbf Mon Sep 17 00:00:00 2001 From: Dmitry Borzenin Date: Fri, 7 Feb 2020 16:51:22 +0300 Subject: [PATCH 3/5] Refactoring in NewsSlag parser --- apps/utils/parsers.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/utils/parsers.py b/apps/utils/parsers.py index 30ed754e..073aa1e4 100644 --- a/apps/utils/parsers.py +++ b/apps/utils/parsers.py @@ -1,9 +1,9 @@ class NewsSlug: - def __init__(self, value=None, locale=None, count=0): + def __init__(self, value=None, country_code=None, count=0): self.value = value - self.locale = locale + self.country_code = country_code self.count = count @classmethod @@ -13,10 +13,10 @@ class NewsSlug: if len(rest) >= 1 and rest[-1] in country_codes: instance.value = '-'.join([slug, *rest[:-1]]) - instance.locale = rest[-1] + instance.country_code = rest[-1] elif len(rest) >= 2 and rest[-1].isdigit() and rest[-2] in country_codes: instance.value = '-'.join([slug, *rest[:-2]]) - instance.locale = rest[-2] + instance.country_code = rest[-2] instance.count = int(rest[-1]) else: instance.value = '-'.join([slug, *rest]) @@ -31,8 +31,8 @@ class NewsSlug: raise ValueError('No value for slug') slug_parts = [self.value] - if self.locale is not None: - slug_parts.append(self.locale) + if self.country_code is not None: + slug_parts.append(self.country_code) if self.count != 0: slug_parts.append(str(self.count)) @@ -40,4 +40,4 @@ class NewsSlug: return '-'.join(slug_parts) def __repr__(self): - return f'<{self.__class__.__name__} {self.value}, {self.locale}, {self.count}>' + return f'<{self.__class__.__name__} {self.value}, {self.country_code}, {self.count}>' From 06137fcccfee93b102897f99808cfee0bc8e9188 Mon Sep 17 00:00:00 2001 From: Dmitry Borzenin Date: Fri, 7 Feb 2020 16:52:48 +0300 Subject: [PATCH 4/5] Refactoring in News.create_duplicate --- apps/news/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/news/models.py b/apps/news/models.py index da860c50..7c585148 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -370,11 +370,12 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, slug = NewsSlug.parse(raw_slug, country_codes) similar_slugs = sorted(x for x in all_slugs if NewsSlug.parse(x, country_codes).value == slug.value) if len(similar_slugs) == 0: - new_slugs[locale] = NewsSlug(slug.value, new_country.code) + # It is impossible because at least current instance has slug + raise ValueError('Duplicating unsaved object') else: last_slug = NewsSlug.parse(similar_slugs[-1], country_codes) new_slug = NewsSlug(slug.value, new_country.code, last_slug.count) - if last_slug.locale is not None: + if last_slug.country_code is not None: new_slug.count += 1 new_slugs[locale] = str(new_slug) From afc39a6257f80ce3d508876317cb4fcf052628d4 Mon Sep 17 00:00:00 2001 From: Dmitry Borzenin Date: Fri, 7 Feb 2020 16:53:25 +0300 Subject: [PATCH 5/5] Add comments on create_duplicate and NewsSlug parser --- apps/news/models.py | 7 +++++++ apps/utils/parsers.py | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/apps/news/models.py b/apps/news/models.py index 7c585148..24c5df11 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -361,6 +361,8 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, def create_duplicate(self, new_country, view_count_model): country_codes = list(Country.objects.all().values_list('code', flat=True)) + + # Get all existed slugs all_slugs = {slug_value for slug_dict in News.objects.all().values_list('slugs', flat=True) for slug_value in slug_dict.values()} @@ -368,12 +370,17 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, new_slugs = {} for locale, raw_slug in self.slugs.items(): slug = NewsSlug.parse(raw_slug, country_codes) + + # all slugs LIKE% slug similar_slugs = sorted(x for x in all_slugs if NewsSlug.parse(x, country_codes).value == slug.value) + if len(similar_slugs) == 0: # It is impossible because at least current instance has slug raise ValueError('Duplicating unsaved object') else: + # The last slug in similar_slugs is slug with largest count last_slug = NewsSlug.parse(similar_slugs[-1], country_codes) + new_slug = NewsSlug(slug.value, new_country.code, last_slug.count) if last_slug.country_code is not None: new_slug.count += 1 diff --git a/apps/utils/parsers.py b/apps/utils/parsers.py index 073aa1e4..dc84a60e 100644 --- a/apps/utils/parsers.py +++ b/apps/utils/parsers.py @@ -12,13 +12,19 @@ class NewsSlug: instance = NewsSlug() if len(rest) >= 1 and rest[-1] in country_codes: + # It is like 'slug-en' + instance.value = '-'.join([slug, *rest[:-1]]) instance.country_code = rest[-1] elif len(rest) >= 2 and rest[-1].isdigit() and rest[-2] in country_codes: + # It is like 'slug-en-1' + instance.value = '-'.join([slug, *rest[:-2]]) instance.country_code = rest[-2] instance.count = int(rest[-1]) else: + # It is like 'slug' + instance.value = '-'.join([slug, *rest]) return instance