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 }} Lookup - {% 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 %}{% 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 %}{% 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")}), )