Repository: fidals/shopelectro

Issue:
models.py:240-242: - refactor Tag.serialize_* methods -...
The puzzle `195-08ad816e` (from #195) in [`shopelectro/models.py`](https://github.com/fidals/shopelectro/blob/master/shopelectro/models.py) (lines 240-242) has to be resolved: "- refactor Tag.serialize_* methods - they must take argument `List[Tag]` as well as `List[Tuple[TagGroup, Tag]]` - they should be standalone functions, not static methods"

The puzzle was created by duker33 on 13-Nov-17. 

Estimate: 0 minutes, role: IMP.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is _removed_ from the source code. Here is more about [PDD](http://www.yegor256.com/2009/03/04/pdd.html) and [about me](http://www.yegor256.com/2017/04/05/pdd-in-action.html).
models.py:240-242: - refactor Tag.serialize_* methods -...
The puzzle `195-08ad816e` (from #195) in [`shopelectro/models.py`](https://github.com/fidals/shopelectro/blob/master/shopelectro/models.py) (lines 240-242) has to be resolved: "- refactor Tag.serialize_* methods - they must take argument `List[Tag]` as well as `List[Tuple[TagGroup, Tag]]` - they should be standalone functions, not static methods"

The puzzle was created by duker33 on 13-Nov-17. 

Estimate: 0 minutes, role: IMP.

If you have any technical questions, don't ask me, submit new tickets instead. The task will be "done" when the problem is fixed and the text of the puzzle is _removed_ from the source code. Here is more about [PDD](http://www.yegor256.com/2009/03/04/pdd.html) and [about me](http://www.yegor256.com/2017/04/05/pdd-in-action.html).


Discussion:
@artemiyds2 @duker33 please pay attention to this new issue.
@artemiyds2 @duker33 please pay attention to this new issue.

Resolving patch:
diff --git a/shopelectro/models.py b/shopelectro/models.py
--- a/shopelectro/models.py
+++ b/shopelectro/models.py
@@ -236,33 +236,6 @@ def save(self, *args, **kwargs):
             )
         super(Tag, self).save(*args, **kwargs)
 
-    """
-    @todo #195 - refactor Tag.serialize_* methods
-     - they must take argument `List[Tag]` as well as `List[Tuple[TagGroup, Tag]]`
-     - they should be standalone functions, not static methods
-    """
-    @staticmethod
-    def serialize_tags(
-        pairs: List[Tuple[TagGroup, 'Tag']],
-        field_name: str,
-        type_delimiter: str,
-        group_delimiter: str
-    ) -> str:
-        _, tags_by_group = zip(*pairs)
-        return group_delimiter.join(
-            type_delimiter.join(getattr(tag, field_name) for tag in tags)
-            for tags in tags_by_group
-        )
-
-    @staticmethod
-    def serialize_url_tags(tags: List[Tuple[TagGroup, 'Tag']]) -> str:
-        return Tag.serialize_tags(
-            pairs=tags,
-            field_name='slug',
-            type_delimiter=settings.TAGS_URL_DELIMITER,
-            group_delimiter=settings.TAG_GROUPS_URL_DELIMITER
-        )
-
     @staticmethod
     def parse_url_tags(tags: str) -> list:
         groups = tags.split(settings.TAGS_URL_DELIMITER)
@@ -270,11 +243,36 @@ def parse_url_tags(tags: str) -> list:
             group.split(settings.TAG_GROUPS_URL_DELIMITER) for group in groups
         ))
 
-    @staticmethod
-    def serialize_title_tags(tags: list) -> str:
-        return Tag.serialize_tags(
-            pairs=tags,
-            field_name='name',
-            type_delimiter=settings.TAGS_TITLE_DELIMITER,
-            group_delimiter=settings.TAG_GROUPS_TITLE_DELIMITER
-        )
+
+def serialize_tags(
+    tags: TagQuerySet,
+    field_name: str,
+    type_delimiter: str,
+    group_delimiter: str,
+) -> str:
+    group_tags_map = tags.get_group_tags_pairs()
+
+    _, tags_by_group = zip(*group_tags_map)
+
+    return group_delimiter.join(
+        type_delimiter.join(getattr(tag, field_name) for tag in tags_list)
+        for tags_list in tags_by_group
+    )
+
+
+def serialize_tags_to_url(tags: TagQuerySet) -> str:
+    return serialize_tags(
+        tags=tags,
+        field_name='slug',
+        type_delimiter=settings.TAGS_URL_DELIMITER,
+        group_delimiter=settings.TAG_GROUPS_URL_DELIMITER
+    )
+
+
+def serialize_tags_to_title(tags: TagQuerySet) -> str:
+    return serialize_tags(
+        tags=tags,
+        field_name='name',
+        type_delimiter=settings.TAGS_TITLE_DELIMITER,
+        group_delimiter=settings.TAG_GROUPS_TITLE_DELIMITER
+    )
diff --git a/shopelectro/sitemaps.py b/shopelectro/sitemaps.py
--- a/shopelectro/sitemaps.py
+++ b/shopelectro/sitemaps.py
@@ -40,7 +40,7 @@ def items(self):
 
 
 def get_categories_with_tags() -> Generator[
-    Tuple[Category, Tuple[TagGroup, Tag]], None, None
+    Tuple[Category, Tag], None, None
 ]:
     """
     Return all unique Category+TagGroup pairs.
@@ -53,7 +53,7 @@ def get_categories_with_tags() -> Generator[
         tags = Tag.objects.filter(products__in=products).distinct()
         for group_name, group_tags in tags.get_group_tags_pairs():
             for group_tag in group_tags:
-                yield category, (group_name, [group_tag])
+                yield category, group_tag
 
 
 class CategoryWithTagsSitemap(AbstractSitemap):
@@ -64,11 +64,10 @@ def items(self):
         return list(get_categories_with_tags())
 
     def location(self, item):
-        category, tags = item
-        tags_slug = Tag.serialize_url_tags([tags])
+        category, tag = item
         return reverse('category', kwargs={
             'slug': category.page.slug,
-            'tags': tags_slug,
+            'tags': tag.slug,
         })
 
 
diff --git a/shopelectro/views/catalog.py b/shopelectro/views/catalog.py
--- a/shopelectro/views/catalog.py
+++ b/shopelectro/views/catalog.py
@@ -152,9 +152,7 @@ def get_context_data(self, **kwargs):
                 .distinct(sorting_option.lstrip('-'))
             )
 
-            tag_titles = models.Tag.serialize_title_tags(
-                tags.get_group_tags_pairs()
-            )
+            tag_titles = models.serialize_tags_to_title(tags)
 
         def template_context(page, tag_titles, tags):
             return {


Test patch:
diff --git a/shopelectro/tests/tests_views.py b/shopelectro/tests/tests_views.py
--- a/shopelectro/tests/tests_views.py
+++ b/shopelectro/tests/tests_views.py
@@ -18,7 +18,7 @@
 from django.urls import reverse
 from django.utils.translation import ugettext as _
 
-from shopelectro.models import Category, Product, Tag, TagGroup, TagQuerySet
+from shopelectro.models import Category, Product, Tag, TagGroup, TagQuerySet, serialize_tags_to_url
 from shopelectro.views.service import generate_md5_for_ya_kassa, YANDEX_REQUEST_PARAM
 
 
@@ -33,7 +33,7 @@ def reverse_category_url(
     if tags:
         # PyCharm's option:
         # noinspection PyTypeChecker
-        tags_slug = Tag.serialize_url_tags(tags.get_group_tags_pairs())
+        tags_slug = serialize_tags_to_url(tags)
         route_kwargs['tags'] = tags_slug
     if sorting is not None:
         route_kwargs['sorting'] = sorting