From 5d7075ee2eeb97567cd7282165798947922a0e04 Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Sat, 21 Jun 2025 22:49:34 +0300 Subject: [PATCH] **Features**: 1) Add `unicode_slugify_function` for advanced slugify handling; 2) Replace default slugify method with `unicode_slugify_function` in models; 3) Introduce `python-slugify` as a project dependency for Unicode slugification; **Fixes**: 1) Remove redundant `slugify` import from `core/models.py`; **Extra**: 1) Update `poetry.lock` and `pyproject.toml` to lock `python-slugify@8.0.4` and refine dependency definitions; 2) Improve readability of debug logging in `TweakedAutoSlugField`. --- core/models.py | 9 ++++----- core/utils/db.py | 17 ++++++++++++++++- poetry.lock | 19 ++++++++++++++++++- pyproject.toml | 3 ++- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/core/models.py b/core/models.py index e4ddbdc9..40c84e3f 100644 --- a/core/models.py +++ b/core/models.py @@ -35,7 +35,6 @@ from django.http import Http404 from django.utils import timezone from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode -from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from django_extensions.db.fields import AutoSlugField from django_prometheus.models import ExportModelOperationsMixin @@ -51,7 +50,7 @@ from core.utils import ( get_product_uuid_as_path, get_random_code, ) -from core.utils.db import TweakedAutoSlugField +from core.utils.db import TweakedAutoSlugField, unicode_slugify_function from core.utils.lists import FAILED_STATUSES from core.validators import validate_category_image_dimensions from evibes.settings import CURRENCY_CODE @@ -220,7 +219,7 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): "parent__name", "name", ), - slugify_function=slugify, + slugify_function=unicode_slugify_function, allow_unicode=True, unique=True, editable=False, @@ -297,7 +296,7 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel): max_length=88, overwrite=True, null=True, - slugify_function=slugify, + slugify_function=unicode_slugify_function, verbose_name=_("brand slug"), ) priority: int = PositiveIntegerField( # type: ignore @@ -376,7 +375,7 @@ class Product(ExportModelOperationsMixin("product"), NiceModel): overwrite=True, allow_unicode=True, unique=True, - slugify_function=slugify, + slugify_function=unicode_slugify_function, editable=False, null=True, ) diff --git a/core/utils/db.py b/core/utils/db.py index 3588490c..0371879c 100644 --- a/core/utils/db.py +++ b/core/utils/db.py @@ -4,9 +4,11 @@ from django.db.models import Model from django.db.models.constants import LOOKUP_SEP from django.utils.translation import gettext_lazy as _ from django_extensions.db.fields import AutoSlugField +from slugify import slugify logger = logging.getLogger(__name__) + def list_to_queryset(model: Model, data: list): if not isinstance(model, Model): raise ValueError(_(f"{model} must be model")) @@ -17,6 +19,17 @@ def list_to_queryset(model: Model, data: list): return model.objects.filter(pk__in=pk_list) +def unicode_slugify_function(content): + return slugify( + text=content, + allow_unicode=True, + max_length=88, + word_boundary=True, + save_order=True, + regex_pattern=r"/", + ) + + class TweakedAutoSlugField(AutoSlugField): def get_slug_fields(self, model_instance, lookup_value): if callable(lookup_value): @@ -25,7 +38,9 @@ class TweakedAutoSlugField(AutoSlugField): lookup_value_path = lookup_value.split(LOOKUP_SEP) attr = model_instance - logger.debug(f"get_slug_fields: lookup_value_path is {lookup_value_path} and attr is {attr}") + logger.debug( + f"get_slug_fields: lookup_value_path is {lookup_value_path} and attr is {attr}" + ) for elem in lookup_value_path: try: diff --git a/poetry.lock b/poetry.lock index 5c6b8ddb..7b663f20 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4039,6 +4039,23 @@ files = [ [package.extras] dev = ["backports.zoneinfo", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec", "mypy", "orjson", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] +[[package]] +name = "python-slugify" +version = "8.0.4" +description = "A Python slugify application that also handles Unicode" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, + {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, +] + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + [[package]] name = "pytz" version = "2025.2" @@ -5166,4 +5183,4 @@ worker = ["celery", "celery-prometheus-exporter", "django-celery-beat", "django- [metadata] lock-version = "2.0" python-versions = ">=3.12,<3.13" -content-hash = "2af805bf62515a47ea6f4649913482e4af8f8831a1236e1fa1400ba82dd9b4e0" +content-hash = "659721d93224050ebe572b017a80d45826b288764427c24bd07fbd35b704fa48" diff --git a/pyproject.toml b/pyproject.toml index 0225f953..6a67cac4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,7 @@ polib = "1.2.0" poetry-core = "2.1.3" PyJWT = "2.9.0" python = ">=3.12,<3.13" +python-slugify = "8.0.4" psutil = "6.1.1" psycopg2 = "2.9.10" pydantic = "2.9.2" @@ -76,7 +77,7 @@ ruff = "0.12.0" sentry-sdk = { extras = ["django", "celery", "opentelemetry", "redis"], version = "2.27.0" } six = "1.17.0" swapper = "1.4.0" -yapf = "^0.43.0" +yapf = "0.43.0" zeep = "4.3.1" [tool.poetry.group.dev.dependencies]