diff --git a/categories/admin.py b/categories/admin.py
index abf3f72..d77349a 100644
--- a/categories/admin.py
+++ b/categories/admin.py
@@ -1,7 +1,7 @@
"""Admin interface classes."""
from django import forms
from django.contrib import admin
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from .base import CategoryBaseAdmin, CategoryBaseAdminForm
from .genericcollection import GenericCollectionTabularInline
diff --git a/categories/base.py b/categories/base.py
index f2e5521..756ff13 100644
--- a/categories/base.py
+++ b/categories/base.py
@@ -6,8 +6,8 @@ It provides customizable metadata and its own name space.
from django import forms
from django.contrib import admin
from django.db import models
-from django.utils.encoding import force_text
-from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import force_str
+from django.utils.translation import gettext_lazy as _
from mptt.fields import TreeForeignKey
from mptt.managers import TreeManager
from mptt.models import MPTTModel
@@ -77,7 +77,7 @@ class CategoryBase(MPTTModel):
def __str__(self):
ancestors = self.get_ancestors()
return " > ".join(
- [force_text(i.name) for i in ancestors]
+ [force_str(i.name) for i in ancestors]
+ [
self.name,
]
diff --git a/categories/editor/templatetags/admin_tree_list_tags.py b/categories/editor/templatetags/admin_tree_list_tags.py
index 11088c4..b06001a 100644
--- a/categories/editor/templatetags/admin_tree_list_tags.py
+++ b/categories/editor/templatetags/admin_tree_list_tags.py
@@ -5,7 +5,7 @@ from django.contrib.admin.utils import lookup_field
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.template import Library
-from django.utils.encoding import force_text, smart_text
+from django.utils.encoding import force_str, smart_str
from django.utils.html import conditional_escape, escape, escapejs, format_html
from django.utils.safestring import mark_safe
@@ -53,7 +53,7 @@ def items_for_tree_result(cl, result, form):
allow_tags = True
result_repr = _boolean_icon(value)
else:
- result_repr = smart_text(value)
+ result_repr = smart_str(value)
# Strip HTML tags in the resulting text, except if the
# function has an "allow_tags" attribute set to True.
if not allow_tags:
@@ -80,7 +80,7 @@ def items_for_tree_result(cl, result, form):
except (AttributeError, ObjectDoesNotExist):
pass
- if force_text(result_repr) == "":
+ if force_str(result_repr) == "":
result_repr = mark_safe(" ")
# If list_display_links not defined, add the link tag to the first field
if (first and not cl.list_display_links) or field_name in cl.list_display_links:
@@ -97,12 +97,12 @@ def items_for_tree_result(cl, result, form):
else:
attr = pk
value = result.serializable_value(attr)
- result_id = repr(force_text(value))[1:]
+ result_id = repr(force_str(value))[1:]
first = False
result_id = escapejs(value)
yield mark_safe(
format_html(
- smart_text('<{}{}>{}{}>'),
+ smart_str('<{}{}>{}{}>'),
table_tag,
row_class,
url,
@@ -123,12 +123,12 @@ def items_for_tree_result(cl, result, form):
# can provide fields on a per request basis
if form and field_name in form.fields:
bf = form[field_name]
- result_repr = mark_safe(force_text(bf.errors) + force_text(bf))
+ result_repr = mark_safe(force_str(bf.errors) + force_str(bf))
else:
result_repr = conditional_escape(result_repr)
- yield mark_safe(smart_text("
%s | " % (row_class, result_repr)))
+ yield mark_safe(smart_str("%s | " % (row_class, result_repr)))
if form and not form[cl.model._meta.pk.name].is_hidden:
- yield mark_safe(smart_text("%s | " % force_text(form[cl.model._meta.pk.name])))
+ yield mark_safe(smart_str("%s | " % force_str(form[cl.model._meta.pk.name])))
class TreeList(list):
diff --git a/categories/editor/tree_editor.py b/categories/editor/tree_editor.py
index d528c95..870b9c4 100644
--- a/categories/editor/tree_editor.py
+++ b/categories/editor/tree_editor.py
@@ -8,7 +8,7 @@ from django.contrib.admin.views.main import ChangeList
from django.db.models.query import QuerySet
from django.http import HttpResponseRedirect
from django.shortcuts import render
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from . import settings
@@ -150,8 +150,8 @@ class TreeEditor(admin.ModelAdmin):
"""The 'change list' admin view for this model."""
from django.contrib.admin.views.main import ERROR_FLAG
from django.core.exceptions import PermissionDenied
- from django.utils.encoding import force_text
- from django.utils.translation import ungettext
+ from django.utils.encoding import force_str
+ from django.utils.translation import ngettext
opts = self.model._meta
app_label = opts.app_label
@@ -199,6 +199,22 @@ class TreeEditor(admin.ModelAdmin):
self.list_editable,
self,
)
+ elif django.VERSION < (4, 0):
+ params = (
+ request,
+ self.model,
+ list_display,
+ self.list_display_links,
+ self.list_filter,
+ self.date_hierarchy,
+ self.search_fields,
+ self.list_select_related,
+ self.list_per_page,
+ self.list_max_show_all,
+ self.list_editable,
+ self,
+ self.sortable_by,
+ )
else:
params = (
request,
@@ -214,6 +230,7 @@ class TreeEditor(admin.ModelAdmin):
self.list_editable,
self,
self.sortable_by,
+ self.search_help_text,
)
cl = TreeChangeList(*params)
except IncorrectLookupParameters:
@@ -256,16 +273,16 @@ class TreeEditor(admin.ModelAdmin):
if changecount:
if changecount == 1:
- name = force_text(opts.verbose_name)
+ name = force_str(opts.verbose_name)
else:
- name = force_text(opts.verbose_name_plural)
+ name = force_str(opts.verbose_name_plural)
msg = (
- ungettext(
+ ngettext(
"%(count)s %(name)s was changed successfully.",
"%(count)s %(name)s were changed successfully.",
changecount,
)
- % {"count": changecount, "name": name, "obj": force_text(obj)}
+ % {"count": changecount, "name": name, "obj": force_str(obj)}
)
self.message_user(request, msg)
@@ -303,11 +320,11 @@ class TreeEditor(admin.ModelAdmin):
if django.VERSION[0] == 1 and django.VERSION[1] < 4:
context["root_path"] = self.admin_site.root_path
elif django.VERSION[0] == 1 or (django.VERSION[0] == 2 and django.VERSION[1] < 1):
- selection_note_all = ungettext("%(total_count)s selected", "All %(total_count)s selected", cl.result_count)
+ selection_note_all = ngettext("%(total_count)s selected", "All %(total_count)s selected", cl.result_count)
context.update(
{
- "module_name": force_text(opts.verbose_name_plural),
+ "module_name": force_str(opts.verbose_name_plural),
"selection_note": _("0 of %(cnt)s selected") % {"cnt": len(cl.result_list)},
"selection_note_all": selection_note_all % {"total_count": cl.result_count},
}
diff --git a/categories/models.py b/categories/models.py
index 0cba3fb..6be9132 100644
--- a/categories/models.py
+++ b/categories/models.py
@@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core.files.images import get_image_dimensions
from django.db import models
from django.urls import reverse
-from django.utils.encoding import force_text
+from django.utils.encoding import force_str
try:
from django.contrib.contenttypes.fields import GenericForeignKey
@@ -13,7 +13,7 @@ except ImportError:
from django.contrib.contenttypes.generic import GenericForeignKey
from django.core.files.storage import get_storage_class
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from .base import CategoryBase
from .settings import (
@@ -72,7 +72,7 @@ class Category(CategoryBase):
ancestors = list(self.get_ancestors()) + [
self,
]
- return prefix + "/".join([force_text(i.slug) for i in ancestors]) + "/"
+ return prefix + "/".join([force_str(i.slug) for i in ancestors]) + "/"
if RELATION_MODELS:
diff --git a/categories/registration.py b/categories/registration.py
index 793c908..1df2870 100644
--- a/categories/registration.py
+++ b/categories/registration.py
@@ -3,13 +3,13 @@ These functions handle the adding of fields to other models.
"""
from typing import Optional, Type, Union
-import collections
+from collections.abc import Iterable
from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured
from django.db.models import CASCADE, ForeignKey, ManyToManyField
# from settings import self._field_registry, self._model_registry
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from . import fields
@@ -26,9 +26,7 @@ class Registry(object):
self._field_registry = {}
self._model_registry = {}
- def register_model(
- self, app: str, model_name, field_type: str, field_definitions: Union[str, collections.Iterable]
- ):
+ def register_model(self, app: str, model_name, field_type: str, field_definitions: Union[str, Iterable]):
"""
Registration process for Django 1.7+.
@@ -41,15 +39,13 @@ class Registry(object):
Raises:
ImproperlyConfigured: For incorrect parameter types or missing model.
"""
- import collections
-
from django.apps import apps
app_label = app
if isinstance(field_definitions, str):
field_definitions = [field_definitions]
- elif not isinstance(field_definitions, collections.Iterable):
+ elif not isinstance(field_definitions, Iterable):
raise ImproperlyConfigured(
_("Field configuration for %(app)s should be a string or iterable") % {"app": app}
)
diff --git a/categories/settings.py b/categories/settings.py
index 03519fe..6b0db82 100644
--- a/categories/settings.py
+++ b/categories/settings.py
@@ -3,7 +3,7 @@ import collections
from django.conf import settings
from django.db.models import Q
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
DEFAULT_SETTINGS = {
"ALLOW_SLUG_CHANGE": False,
diff --git a/categories/templates/admin/edit_inline/gen_coll_tabular.html b/categories/templates/admin/edit_inline/gen_coll_tabular.html
index 3a240ca..d6e542c 100644
--- a/categories/templates/admin/edit_inline/gen_coll_tabular.html
+++ b/categories/templates/admin/edit_inline/gen_coll_tabular.html
@@ -43,12 +43,12 @@
{{ field.contents }}
{% else %}
{{ field.field.errors.as_ul }}
- {% ifequal field.field.name inline_admin_formset.formset.ct_fk_field %}
+ {% if field.field.name == inline_admin_formset.formset.ct_fk_field %}
{{ field.field }}
- {% else %}{{ field.field }} {% endifequal %}
+ {% else %}{{ field.field }} {% endif %}
{% endif %}
{% endfor %}
diff --git a/categories/templates/categories/ancestors_ul.html b/categories/templates/categories/ancestors_ul.html
index d9173e2..bedb5e5 100644
--- a/categories/templates/categories/ancestors_ul.html
+++ b/categories/templates/categories/ancestors_ul.html
@@ -4,8 +4,8 @@
{% if structure.new_level %}-
{% else %}
-
{% endif %}
- {% ifequal node category %}{{ node.name }}
+ {% if node == category %}{{ node.name }}
{% else %}{{ node.name }}
- {% endifequal %}
+ {% endif %}
{% for level in structure.closed_levels %}
{% endfor %}
{% endfor %}
diff --git a/categories/templates/categories/ul_tree.html b/categories/templates/categories/ul_tree.html
index 891e298..649f996 100644
--- a/categories/templates/categories/ul_tree.html
+++ b/categories/templates/categories/ul_tree.html
@@ -4,8 +4,8 @@
{% if structure.new_level %}-
{% else %}
-
{% endif %}
- {% ifequal node category %}{{ node.name }}
+ {% if node == category %}{{ node.name }}
{% else %}{{ node.name }}
- {% endifequal %}
+ {% endif %}
{% for level in structure.closed_levels %}
{% endfor %}
{% endfor %}{% endspaceless %}
diff --git a/categories/tests/test_admin.py b/categories/tests/test_admin.py
index 4875889..fdbbd32 100644
--- a/categories/tests/test_admin.py
+++ b/categories/tests/test_admin.py
@@ -1,7 +1,7 @@
from django.contrib.auth.models import User
from django.test import Client, TestCase
from django.urls import reverse
-from django.utils.encoding import smart_text
+from django.utils.encoding import smart_str
from categories.models import Category
@@ -16,7 +16,7 @@ class TestCategoryAdmin(TestCase):
url = reverse("admin:categories_category_add")
data = {
"parent": "",
- "name": smart_text("Parent Catégory"),
+ "name": smart_str("Parent Catégory"),
"thumbnail": "",
"filename": "",
"active": "on",
@@ -38,7 +38,7 @@ class TestCategoryAdmin(TestCase):
self.assertEqual(1, Category.objects.count())
# update parent
- data.update({"name": smart_text("Parent Catégory (Changed)")})
+ data.update({"name": smart_str("Parent Catégory (Changed)")})
resp = self.client.post(reverse("admin:categories_category_change", args=(1,)), data=data)
self.assertEqual(resp.status_code, 302)
self.assertEqual(1, Category.objects.count())
@@ -47,8 +47,8 @@ class TestCategoryAdmin(TestCase):
data.update(
{
"parent": "1",
- "name": smart_text("Child Catégory"),
- "slug": smart_text("child-category"),
+ "name": smart_str("Child Catégory"),
+ "slug": smart_str("child-category"),
}
)
resp = self.client.post(url, data=data)
diff --git a/categories/urls.py b/categories/urls.py
index ecb9649..a7eaa0d 100644
--- a/categories/urls.py
+++ b/categories/urls.py
@@ -1,5 +1,5 @@
"""URL patterns for the categories app."""
-from django.conf.urls import url
+from django.urls import path, re_path
from django.views.generic import ListView
from . import views
@@ -7,6 +7,6 @@ from .models import Category
categorytree_dict = {"queryset": Category.objects.filter(level=0)}
-urlpatterns = (url(r"^$", ListView.as_view(**categorytree_dict), name="categories_tree_list"),)
+urlpatterns = (path("", ListView.as_view(**categorytree_dict), name="categories_tree_list"),)
-urlpatterns += (url(r"^(?P.+)/$", views.category_detail, name="categories_category"),)
+urlpatterns += (re_path(r"^(?P.+)/$", views.category_detail, name="categories_category"),)
diff --git a/categories/views.py b/categories/views.py
index cb81054..9ec620e 100644
--- a/categories/views.py
+++ b/categories/views.py
@@ -4,7 +4,7 @@ from typing import Optional
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django.template.loader import select_template
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from .models import Category
diff --git a/example/urls.py b/example/urls.py
index b20f351..615b8b7 100644
--- a/example/urls.py
+++ b/example/urls.py
@@ -1,8 +1,9 @@
"""URL patterns for the example project."""
import os
-from django.conf.urls import include, url
+from django.conf.urls import include
from django.contrib import admin
+from django.urls import path, re_path
from django.views.static import serve
admin.autodiscover()
@@ -17,12 +18,14 @@ urlpatterns = (
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
- url(r"^admin/", admin.site.urls),
- url(r"^categories/", include("categories.urls")),
+ path("admin/", admin.site.urls),
+ path("categories/", include("categories.urls")),
# r'^cats/', include('categories.urls')),
- url(r"^static/categories/(?P.*)$", serve, {"document_root": ROOT_PATH + "/categories/media/categories/"}),
+ re_path(
+ r"^static/categories/(?P.*)$", serve, {"document_root": ROOT_PATH + "/categories/media/categories/"}
+ ),
# (r'^static/editor/(?P.*)$', 'django.views.static.serve',
# {'document_root': ROOT_PATH + '/editor/media/editor/',
# 'show_indexes':True}),
- url(r"^static/(?P.*)$", serve, {"document_root": os.path.join(ROOT_PATH, "example", "static")}),
+ re_path(r"^static/(?P.*)$", serve, {"document_root": os.path.join(ROOT_PATH, "example", "static")}),
)