From c40e7e732beb71ec1cd38a91c3157b762661324c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 5 Oct 2018 15:59:21 +0200 Subject: [PATCH 01/10] make Category.slug unique --- categories/base.py | 2 +- .../migrations/0005_unique_category_slug.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 categories/migrations/0005_unique_category_slug.py diff --git a/categories/base.py b/categories/base.py index f1ed01d6..74c3fdec 100644 --- a/categories/base.py +++ b/categories/base.py @@ -46,7 +46,7 @@ class CategoryBase(MPTTModel): verbose_name=_("parent"), ) name = models.CharField(max_length=100, verbose_name=_("name")) - slug = models.SlugField(verbose_name=_("slug")) + slug = models.SlugField(verbose_name=_("slug"), unique=True) active = models.BooleanField(default=True, verbose_name=_("active")) objects = CategoryManager() diff --git a/categories/migrations/0005_unique_category_slug.py b/categories/migrations/0005_unique_category_slug.py new file mode 100644 index 00000000..e3071e90 --- /dev/null +++ b/categories/migrations/0005_unique_category_slug.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.9 on 2018-10-05 13:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("categories", "0004_auto_20200517_1832"), + ] + + operations = [ + migrations.AlterField( + model_name="category", + name="slug", + field=models.SlugField(unique=True, verbose_name="slug"), + ), + ] From b52ce9c839aabada19bf8c2c89a2505119de09c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 13 Mar 2020 15:49:35 +0100 Subject: [PATCH 02/10] make datamigration for non-unique slugs, test the migration --- .../migrations/0005_unique_category_slug.py | 20 ++++++++- categories/tests/test_migrations.py | 42 +++++++++++++++++++ tox.ini | 5 +++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 categories/tests/test_migrations.py diff --git a/categories/migrations/0005_unique_category_slug.py b/categories/migrations/0005_unique_category_slug.py index e3071e90..1be7e62e 100644 --- a/categories/migrations/0005_unique_category_slug.py +++ b/categories/migrations/0005_unique_category_slug.py @@ -2,14 +2,32 @@ from django.db import migrations, models +from categories.models import Category -class Migration(migrations.Migration): +def make_slugs_unique(apps, schema_editor): + duplicates = Category.tree.values("slug").annotate(slug_count=models.Count("slug")).filter(slug_count__gt=1) + category_objs = [] + for duplicate in duplicates: + slug = duplicate["slug"] + categories = Category.tree.filter(slug=slug) + count = categories.count() + i = 0 + for category in categories.all(): + if i != 0: + category.slug = "{}-{}".format(slug, str(i).zfill(len(str(count)))) + category_objs.append(category) + i += 1 + Category.objects.bulk_update(category_objs, ["slug"]) + + +class Migration(migrations.Migration): dependencies = [ ("categories", "0004_auto_20200517_1832"), ] operations = [ + migrations.RunPython(make_slugs_unique, reverse_code=migrations.RunPython.noop), migrations.AlterField( model_name="category", name="slug", diff --git a/categories/tests/test_migrations.py b/categories/tests/test_migrations.py new file mode 100644 index 00000000..211955da --- /dev/null +++ b/categories/tests/test_migrations.py @@ -0,0 +1,42 @@ +import sys + +if sys.version_info >= (3, 0): + from django_test_migrations.contrib.unittest_case import MigratorTestCase + + class TestMigrations(MigratorTestCase): + migrate_from = ("categories", "0004_auto_20200517_1832") + migrate_to = ("categories", "0005_unique_category_slug") + + def prepare(self): + Category = self.old_state.apps.get_model("categories", "Category") + Category.tree.create(slug="foo", lft=0, rght=0, tree_id=0, level=0) + Category.tree.create(slug="foo", lft=0, rght=0, tree_id=0, level=0) + Category.tree.create(slug="foo", lft=0, rght=0, tree_id=0, level=0) + for i in range(1, 12): + Category.tree.create(slug="bar", lft=0, rght=0, tree_id=0, level=0) + Category.tree.create(slug="baz", lft=0, rght=0, tree_id=0, level=0) + assert Category.tree.count() == 15 + + def test_unique_slug_migration(self): + Category = self.new_state.apps.get_model("categories", "Category") + + self.assertListEqual( + list(Category.tree.values_list("slug", flat=True)), + [ + "foo", + "foo-1", + "foo-2", + "bar", + "bar-01", + "bar-02", + "bar-03", + "bar-04", + "bar-05", + "bar-06", + "bar-07", + "bar-08", + "bar-09", + "bar-10", + "baz", + ], + ) diff --git a/tox.ini b/tox.ini index f3440727..6dbcb2f3 100644 --- a/tox.ini +++ b/tox.ini @@ -37,6 +37,11 @@ deps= pillow ipdb codecov + django-test-migrations + django21: django-test-migrations<=1.2.0 + django22: django-test-migrations<=1.2.0 + django3: django-test-migrations<=1.2.0 + django31: django-test-migrations<=1.2.0 -r{toxinidir}/requirements.txt commands= From d1dd266bd2ecc7b08ba3d9635a03577e11371a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 13 Mar 2020 15:50:14 +0100 Subject: [PATCH 03/10] fix duplicate slugs in tests --- categories/fixtures/musicgenres.json | 2 +- categories/tests/test_category_import.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/categories/fixtures/musicgenres.json b/categories/fixtures/musicgenres.json index 38175100..1cf4e4ff 100644 --- a/categories/fixtures/musicgenres.json +++ b/categories/fixtures/musicgenres.json @@ -2292,7 +2292,7 @@ "name": "Country pop", "parent": 142, "level": 1, - "slug": "country-pop", + "slug": "country-pop_1", "lft": 100, "tree_id": 10, "order": 1 diff --git a/categories/tests/test_category_import.py b/categories/tests/test_category_import.py index acd366f5..3c2a5b5f 100644 --- a/categories/tests/test_category_import.py +++ b/categories/tests/test_category_import.py @@ -58,7 +58,7 @@ def testMixingTabsSpaces(self): Should raise an exception. """ string1 = ["cat1", " cat1-1", "\tcat1-2-FAIL!", ""] - string2 = ["cat1", "\tcat1-1", " cat1-2-FAIL!", ""] + string2 = ["cat1a", "\tcat1-1a", " cat1-2-FAIL!", ""] cmd = Command() # raise Exception From 04d77d353ab4ad2778d5b8a0b5698ba6235107e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 13 Mar 2020 20:02:38 +0100 Subject: [PATCH 04/10] fix ValueError in tests --- categories/fields.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/categories/fields.py b/categories/fields.py index 1f44d1ff..25f77d23 100644 --- a/categories/fields.py +++ b/categories/fields.py @@ -7,19 +7,15 @@ class CategoryM2MField(ManyToManyField): """A many to many field to a Category model.""" def __init__(self, **kwargs): - from .models import Category - if "to" in kwargs: kwargs.pop("to") - super(CategoryM2MField, self).__init__(to=Category, **kwargs) + super(CategoryM2MField, self).__init__(to="categories.Category", **kwargs) class CategoryFKField(ForeignKey): """A foreign key to the Category model.""" def __init__(self, **kwargs): - from .models import Category - if "to" in kwargs: kwargs.pop("to") - super(CategoryFKField, self).__init__(to=Category, **kwargs) + super(CategoryFKField, self).__init__(to="categories.Category", **kwargs) From 773188128f9c4b3a1a32ee966d8b6809b9c14088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Thu, 25 Feb 2021 10:45:24 +0100 Subject: [PATCH 05/10] fix migration ref in test and fix test run --- example/settings-testing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/settings-testing.py b/example/settings-testing.py index 2af07026..ecfb5a05 100644 --- a/example/settings-testing.py +++ b/example/settings-testing.py @@ -123,7 +123,7 @@ ), }, "M2M_REGISTRY": { - # 'simpletext.simpletext': {'name': 'categories', 'related_name': 'm2mcats'}, + "simpletext.simpletext": {"name": "categories", "related_name": "m2mcats"}, "flatpages.flatpage": ( {"name": "other_categories", "related_name": "other_cats"}, {"name": "more_categories", "related_name": "more_cats"}, From c7e744d56764a7ac8944deaaa1eb4f01b8c6d9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Mon, 26 Sep 2022 11:18:28 +0200 Subject: [PATCH 06/10] add breaking changes message to CHANGELOG.md --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5565e82b..a36d71b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 2.0.0 (2022-09-xx) + +### WARNING + +**Breaking change:** Starting with version the 2.0.0 the category slugs are unique. +While this brings big advantage for simplified category addressing, it can break projects that are containing categories with duplicated slugs. +If your database contains colliding slugs, they will be automatically renamed by the migration. +Three categories with slugs ``foo`` will be renamed to ``foo``, ``foo-1``, ``foo-2``. +If this causes problems in your project, you can rename the categories yourself before running the migration. + + ## 1.9.4 (2024-04-18) - Remove dependency on unicode-slugify, use Django builtin function From eb78215055bd872aff828ef754cb23182beedbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Tue, 27 Sep 2022 12:49:35 +0200 Subject: [PATCH 07/10] remove support for Django 2.1 --- CHANGELOG.md | 2 ++ tox.ini | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a36d71b9..3377529e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ If your database contains colliding slugs, they will be automatically renamed by Three categories with slugs ``foo`` will be renamed to ``foo``, ``foo-1``, ``foo-2``. If this causes problems in your project, you can rename the categories yourself before running the migration. +- Django 2.1 is no longer supported + ## 1.9.4 (2024-04-18) diff --git a/tox.ini b/tox.ini index 6dbcb2f3..85815df1 100644 --- a/tox.ini +++ b/tox.ini @@ -2,7 +2,6 @@ envlist = begin py37-lint - py{37}-django{21} py{37,38,39}-django{22,3,31} py{37,38,39,310}-django{32} py{38,39,310}-django{40} @@ -22,8 +21,6 @@ python = passenv = GITHUB_* deps= - django2: Django>=2.0,<2.1 - django21: Django>=2.1,<2.2 django22: Django>=2.2,<2.3 django3: Django>=3.0,<3.1 django31: Django>=3.1,<3.2 From bbfe8a9d89821417daa2955499859d73ecf9d9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Wed, 17 Apr 2024 16:36:39 +0200 Subject: [PATCH 08/10] Bumped version for normal release. --- CHANGELOG.md | 2 +- categories/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3377529e..ced72762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 2.0.0 (2022-09-xx) +## 2.0.0-alpha.1 (unreleased) ### WARNING diff --git a/categories/__init__.py b/categories/__init__.py index 35dee15d..cb5e8796 100644 --- a/categories/__init__.py +++ b/categories/__init__.py @@ -1,6 +1,6 @@ """Django categories.""" -__version__ = "1.9.4" +__version__ = "2.0.0-alpha.1" default_app_config = "categories.apps.CategoriesConfig" From 8869bd332e7e3b7c917e739d805e86d900e1a0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 19 Apr 2024 10:55:12 +0200 Subject: [PATCH 09/10] Bumped version for normal release. --- CHANGELOG.md | 2 +- categories/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ced72762..442485ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 2.0.0-alpha.1 (unreleased) +## 2.0.0-alpha.2 (unreleased) ### WARNING diff --git a/categories/__init__.py b/categories/__init__.py index cb5e8796..72924630 100644 --- a/categories/__init__.py +++ b/categories/__init__.py @@ -1,6 +1,6 @@ """Django categories.""" -__version__ = "2.0.0-alpha.1" +__version__ = "2.0.0-alpha.2" default_app_config = "categories.apps.CategoriesConfig" From 539688e45139bc7c8eef0017705ce869384b34ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Wed, 22 May 2024 10:06:05 +0200 Subject: [PATCH 10/10] update changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 442485ca..b2bb0b3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog -## 2.0.0-alpha.2 (unreleased) +## 2.0.0 (2024-05-22) + +- Fixes for old style storages removed in Django 5.1 + +## 2.0.0-alpha.2 (2024-04-19) +## 2.0.0-alpha.1 (2024-04-17) ### WARNING