From 25de55f7c16de06b05e9f7eed663c39846dae8f1 Mon Sep 17 00:00:00 2001
From: Dylann Cordel <cordel.d@free.fr>
Date: Thu, 11 Jul 2024 18:42:51 +0200
Subject: [PATCH] compat 4.2

---
 newsbox/admin.py                            | 44 +++++++++++++--------
 newsbox/models.py                           |  4 +-
 newsbox/urls.py                             | 14 +++----
 newsbox_cms/admin.py                        | 10 +++--
 newsbox_cms/cms_plugins.py                  |  2 +-
 newsbox_cms/models.py                       |  6 +--
 newsbox_i18n/admin.py                       |  2 +-
 newsbox_i18n/models.py                      |  4 +-
 tests/myapp/admin.py                        | 10 ++---
 tests/myapp/urls.py                         |  4 +-
 tests/myapp_all/admin.py                    |  6 +--
 tests/myapp_all/migrations/0001_initial.py  |  8 ++--
 tests/myapp_all/urls.py                     |  6 +--
 tests/myapp_all/urls_news.py                |  4 +-
 tests/myapp_cms/admin.py                    |  6 +--
 tests/myapp_cms/migrations/0001_initial.py  |  2 +-
 tests/myapp_cms/urls.py                     |  6 +--
 tests/myapp_cms/urls_news.py                |  4 +-
 tests/myapp_i18n/migrations/0001_initial.py |  6 +--
 tests/myapp_i18n/urls.py                    |  4 +-
 20 files changed, 83 insertions(+), 69 deletions(-)

diff --git a/newsbox/admin.py b/newsbox/admin.py
index 995fbd8..4502056 100644
--- a/newsbox/admin.py
+++ b/newsbox/admin.py
@@ -7,7 +7,7 @@ import copy
 import itertools
 
 # Django imports
-from django.conf.urls import url
+from django.urls import re_path
 from django.contrib import admin
 from django.contrib import messages
 from django.contrib.admin.models import CHANGE
@@ -19,7 +19,7 @@ try:
     # Django imports
     from django.urls import reverse
 except ImportError:
-    from django.core.urlresolvers import reverse
+    from django.urls import reverse
 
 # Django imports
 from django.http import HttpResponseForbidden
@@ -27,8 +27,8 @@ from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404
 from django.utils import formats
 from django.utils.html import format_html
-from django.utils.translation import ugettext_lazy as _
-from django.utils.translation import ungettext_lazy
+from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ngettext_lazy
 
 # Third Party
 import six
@@ -147,6 +147,10 @@ class NewsboxBaseAdmin(admin.ModelAdmin):
         pfields.update({'newsbox_slug': ('newsbox_title',)})
         return pfields
 
+    @admin.display(
+        description=_('published'),
+        ordering='newsbox_status',
+    )
     def changestatus_link(self, obj):
         if obj.newsbox_status == obj.STATUS_PUBLISHED:
             title = _('Unpublish this %s') % six.text_type(
@@ -166,15 +170,15 @@ class NewsboxBaseAdmin(admin.ModelAdmin):
             obj.get_newsbox_status_display()
         )
 
-    changestatus_link.admin_order_field = 'newsbox_status'
-    changestatus_link.short_description = _('published')
 
+    @admin.display(
+        description=_('pub. date')
+    )
     def newsbox_date_short(self, obj):
         return format_html('<span title="{}">{}</span>',
             formats.date_format(obj.newsbox_publication_start_date, 'DATETIME_FORMAT'),
             formats.date_format(obj.newsbox_publication_start_date, 'SHORT_DATE_FORMAT')
         )
-    newsbox_date_short.short_description = _('pub. date')
 
     def get_fieldsets(self, request, obj=None):
         """
@@ -183,20 +187,22 @@ class NewsboxBaseAdmin(admin.ModelAdmin):
         fieldsets = super(NewsboxBaseAdmin, self).get_fieldsets(request, obj)
         return copy.deepcopy(fieldsets)
 
+    @admin.display(
+        description=_('Title')
+    )
     def get_newsbox_title(self, obj):
         return obj.newsbox_title
-    get_newsbox_title.short_description = _('Title')
 
     def get_urls(self):
         url_prefix = '%s_%s_' % (self.model._meta.model_name, self.model._meta.app_label)
         return [
-            url(r'^([0-9]+)/change-status/$',
+            re_path(r'^([0-9]+)/change-status/$',
                 self.admin_site.admin_view(self.change_status),
                 name='%schange_status' % url_prefix,),
-            url(r'^([0-9]+)/publish/$',
+            re_path(r'^([0-9]+)/publish/$',
                 self.admin_site.admin_view(self.publish_one),
                 name='%spublish_one' % url_prefix,),
-            url(r'^([0-9]+)/unpublish/$',
+            re_path(r'^([0-9]+)/unpublish/$',
                 self.admin_site.admin_view(self.unpublish_one),
                 name='%sunpublish_one' % url_prefix,)
         ] + super(NewsboxBaseAdmin, self).get_urls()
@@ -256,6 +262,9 @@ class NewsboxBaseAdmin(admin.ModelAdmin):
         self.unpublish(request, self.model.objects.filter(pk=news_id))
         return HttpResponseRedirect(request.GET.get('next', '../../'))
 
+    @admin.action(
+        description=_('Publish selected %(verbose_name_plural)s')
+    )
     def publish(self, request, queryset):
         """
         Marks selected news items as published
@@ -290,13 +299,15 @@ class NewsboxBaseAdmin(admin.ModelAdmin):
                 'objtype': self.model._meta.verbose_name,
                 'objtitle': last_obj_ok, })
         else:
-            messages.success(request, ungettext_lazy(
+            messages.success(request, ngettext_lazy(
                 '%(nb)d %(objtype)s has been published',
                 '%(nb)d %(objtype)s have been published',
                 ok) % {'nb': ok,
                        'objtype': self.model._meta.verbose_name_plural,})
-    publish.short_description = _('Publish selected %(verbose_name_plural)s')
 
+    @admin.action(
+        description=_('Archive selected %(verbose_name_plural)s')
+    )
     def unpublish(self, request, queryset):
         """
         Marks selected news items as unpublished
@@ -331,12 +342,11 @@ class NewsboxBaseAdmin(admin.ModelAdmin):
                 'objtype': self.model._meta.verbose_name,
                 'objtitle': last_obj_ok, })
         else:
-            messages.success(request, ungettext_lazy(
+            messages.success(request, ngettext_lazy(
                 '%(nb)d %(objtype)s has been unpublished',
                 '%(nb)d %(objtype)s have been unpublished',
                 ok) % {'nb': ok,
                        'objtype': self.model._meta.verbose_name_plural})
-    unpublish.short_description = _('Archive selected %(verbose_name_plural)s')
 
     def ensure_slug_uniq_queryset(self, request, obj, slug):
         y, m, d = (obj.newsbox_publication_start_date.year,
@@ -373,6 +383,9 @@ class NewsboxAdmin(NewsboxBaseAdmin):
 
 class NewsboxExpiredAdmin(NewsboxBaseAdmin):
 
+    @admin.display(
+        description=_('publication')
+    )
     def newsbox_publication_dates_short(self, obj):
         output = []
         title = []
@@ -397,7 +410,6 @@ class NewsboxExpiredAdmin(NewsboxBaseAdmin):
         output = ('<span> %s </span>' % _('to')).join(output)
         return format_html('<abbr class="newsbox_pub_dates %s" title="%s">%s</abbr>' % (
             css_class, title, output))
-    newsbox_publication_dates_short.short_description = _('publication')
 
     def get_fieldsets(self, request, obj=None):
         fieldsets = super(NewsboxExpiredAdmin, self).get_fieldsets(request, obj)
diff --git a/newsbox/models.py b/newsbox/models.py
index 2b6d00e..a758a07 100644
--- a/newsbox/models.py
+++ b/newsbox/models.py
@@ -14,14 +14,14 @@ try:
     # Django imports
     from django.urls import reverse
 except ImportError:
-    from django.core.urlresolvers import reverse
+    from django.urls import reverse
 
 # Django imports
 from django.db import models
 from django.utils.functional import lazy
 from django.utils.safestring import mark_safe
 from django.utils.timezone import now
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
 
 # Third Party
 import six
diff --git a/newsbox/urls.py b/newsbox/urls.py
index 5e3bac9..3aef07f 100644
--- a/newsbox/urls.py
+++ b/newsbox/urls.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.conf.urls import include, url
+from django.urls import include, re_path
 
 from .models import newsbox_models
 from .views import NewsboxArchiveView, NewsboxYearArchiveView, \
@@ -86,23 +86,23 @@ def get_urls(
 
         if archive_view:
             view = _get_view(archive_view, model, **archive_view_kwargs)
-            model_urls.append(url(root_url, view, name='%slist' % name_prefix))
+            model_urls.append(re_path(root_url, view, name='%slist' % name_prefix))
 
         if year_archive_view:
             view = _get_view(year_archive_view, model, **year_archive_view_kwargs)
-            model_urls.append(url(year_url, view, name='%slist' % name_prefix))
+            model_urls.append(re_path(year_url, view, name='%slist' % name_prefix))
 
         if month_archive_view:
             view = _get_view(month_archive_view, model, **month_archive_view_kwargs)
-            model_urls.append(url(month_url, view, name='%slist' % name_prefix))
+            model_urls.append(re_path(month_url, view, name='%slist' % name_prefix))
 
         if day_archive_view:
             view = _get_view(day_archive_view, model, **day_archive_view_kwargs)
-            model_urls.append(url(day_url, view, name='%slist' % name_prefix))
+            model_urls.append(re_path(day_url, view, name='%slist' % name_prefix))
 
         if detail_view:
             view = _get_view(detail_view, model, **detail_view_kwargs)
-            model_urls.append(url(slug_url, view, name='%sdetail' % name_prefix))
+            model_urls.append(re_path(slug_url, view, name='%sdetail' % name_prefix))
         if model_urls:
-            urls.append(url(r'^%s' % prefix, include(model_urls, namespace=namespace)))
+            urls.append(re_path(r'^%s' % prefix, include(model_urls, namespace=namespace)))
     return urls
diff --git a/newsbox_cms/admin.py b/newsbox_cms/admin.py
index 19b61b1..6ca594f 100644
--- a/newsbox_cms/admin.py
+++ b/newsbox_cms/admin.py
@@ -9,12 +9,12 @@ try:
     # Django imports
     from django.urls import reverse
 except ImportError:
-    from django.core.urlresolvers import reverse
+    from django.urls import reverse
 
 # Django imports
 from django.utils import formats
 from django.utils.html import format_html
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
 
 # Third Party
 import six
@@ -71,6 +71,10 @@ def CustomModelCMSAdminFactory(
                 title = six.text_type(obj)
             return title
 
+        @admin.display(
+            description=edit_link_short_description,
+            ordering=edit_link_admin_order_field,
+        )
         def edit_link(self, obj):
             """
             build the change list edit link
@@ -96,8 +100,6 @@ def CustomModelCMSAdminFactory(
                 title=self.edit_link_title(obj, object_title),
                 edit_label=_("edit object's parameters"))
 
-        edit_link.short_description = edit_link_short_description
-        edit_link.admin_order_field = edit_link_admin_order_field
 
         def get_list_display(self, request):
             list_display = super(CustomModelCMSAdmin, self).get_list_display(request)
diff --git a/newsbox_cms/cms_plugins.py b/newsbox_cms/cms_plugins.py
index 46c609a..81ec916 100644
--- a/newsbox_cms/cms_plugins.py
+++ b/newsbox_cms/cms_plugins.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 
 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 from django.template.loader import select_template
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
 from cms.plugin_base import CMSPluginBase
 from newsbox.models import NewsboxBase
 from newsbox_cms import compat
diff --git a/newsbox_cms/models.py b/newsbox_cms/models.py
index ff71ff2..8459fb8 100644
--- a/newsbox_cms/models.py
+++ b/newsbox_cms/models.py
@@ -4,8 +4,8 @@ from __future__ import unicode_literals
 
 # Django imports
 from django.db import models
-from django.utils.translation import ugettext_lazy as _
-from django.utils.translation import ungettext_lazy
+from django.utils.translation import gettext_lazy as _
+from django.utils.translation import ngettext_lazy
 
 # Third Party
 from cms.models.fields import PageField
@@ -49,7 +49,7 @@ class NewsboxPluginBase(CMSPlugin):
 
     def __str__(self):
         if self.numitems > 0:
-            return six.text_type(ungettext_lazy(
+            return six.text_type(ngettext_lazy(
                 'Display of a news',
                 'Display of %(nb)d news',
                 self.numitems
diff --git a/newsbox_i18n/admin.py b/newsbox_i18n/admin.py
index 569b735..87c12df 100644
--- a/newsbox_i18n/admin.py
+++ b/newsbox_i18n/admin.py
@@ -5,7 +5,7 @@ import copy
 from django.conf import settings
 from parler.admin import TranslatableAdmin
 from django.utils.html import format_html
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
 
 
 def edit_translation_links(obj):
diff --git a/newsbox_i18n/models.py b/newsbox_i18n/models.py
index b9718e4..58d305a 100644
--- a/newsbox_i18n/models.py
+++ b/newsbox_i18n/models.py
@@ -6,10 +6,10 @@ try:
     # Django imports
     from django.urls import reverse
 except ImportError:
-    from django.core.urlresolvers import reverse
+    from django.urls import reverse
 # Django imports
 from django.utils.translation import get_language
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
 
 # Third Party
 from newsbox.models import NewsboxManager
diff --git a/tests/myapp/admin.py b/tests/myapp/admin.py
index 7af6cbf..759f36e 100644
--- a/tests/myapp/admin.py
+++ b/tests/myapp/admin.py
@@ -6,30 +6,31 @@ from newsbox.admin import NewsboxAdmin, NewsboxSEOAdmin, NewsboxExpiredAdmin
 from .models import News, NewsSEO, NewsExpired, NewsComplete, NewsExtended
 
 
+@admin.register(News)
 class NewsAdmin(NewsboxAdmin):
     pass
 
-admin.site.register(News, NewsAdmin)
 
 
+@admin.register(NewsSEO)
 class NewsSEOAdmin(NewsboxSEOAdmin):
     pass
 
-admin.site.register(NewsSEO, NewsSEOAdmin)
 
 
+@admin.register(NewsExpired)
 class NewsExpiredAdmin(NewsboxExpiredAdmin):
     pass
 
-admin.site.register(NewsExpired, NewsExpiredAdmin)
 
 
+@admin.register(NewsComplete)
 class NewsCompleteAdmin(NewsboxSEOAdmin, NewsboxExpiredAdmin):
     pass
 
-admin.site.register(NewsComplete, NewsCompleteAdmin)
 
 
+@admin.register(NewsExtended)
 class NewsExtendedAdmin(NewsboxSEOAdmin, NewsboxExpiredAdmin):
     def get_fieldsets(self, request, obj=None):
         fieldsets = super(NewsExtendedAdmin, self).get_fieldsets(request, obj)
@@ -43,4 +44,3 @@ class NewsExtendedAdmin(NewsboxSEOAdmin, NewsboxExpiredAdmin):
         list_display.append('seo_field')
         return list_display
 
-admin.site.register(NewsExtended, NewsExtendedAdmin)
diff --git a/tests/myapp/urls.py b/tests/myapp/urls.py
index 7f4fa8d..00f6b89 100644
--- a/tests/myapp/urls.py
+++ b/tests/myapp/urls.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.conf.urls import url, include
+from django.urls import include, path
 from django.contrib import admin
 from newsbox.urls import get_urls
 
@@ -12,4 +12,4 @@ news_urls = get_urls(archive_view={'paginate_by': 1},
                      day_archive_view={'paginate_by': 1})
 
 admin.autodiscover()
-urlpatterns = [url(r'^admin/', include(admin.site.urls)), ] + news_urls
+urlpatterns = [path('admin/', include(admin.site.urls)), ] + news_urls
diff --git a/tests/myapp_all/admin.py b/tests/myapp_all/admin.py
index 7d30b60..80b3282 100644
--- a/tests/myapp_all/admin.py
+++ b/tests/myapp_all/admin.py
@@ -10,18 +10,19 @@ from newsbox_i18n.admin import NewsboxI18NAdmin
 from .models import News, NewsComplete, NewsExtended
 
 
+@admin.register(News)
 class NewsAdmin(NewsboxI18NAdmin, NewsboxCMSAdmin):
     pass
 
-admin.site.register(News, NewsAdmin)
 
 
+@admin.register(NewsComplete)
 class NewsCompleteAdmin(NewsboxI18NAdmin, NewsboxCMSAdmin, NewsboxSEOAdmin, NewsboxExpiredAdmin):
     pass
 
-admin.site.register(NewsComplete, NewsCompleteAdmin)
 
 
+@admin.register(NewsExtended)
 class NewsExtendedAdmin(NewsboxI18NAdmin, NewsboxCMSAdmin, NewsboxSEOAdmin, NewsboxExpiredAdmin):
     def get_fieldsets(self, request, obj=None):
         fieldsets = super(NewsExtendedAdmin, self).get_fieldsets(request, obj)
@@ -35,4 +36,3 @@ class NewsExtendedAdmin(NewsboxI18NAdmin, NewsboxCMSAdmin, NewsboxSEOAdmin, News
         list_display.append('seo_field')
         return list_display
 
-admin.site.register(NewsExtended, NewsExtendedAdmin)
diff --git a/tests/myapp_all/migrations/0001_initial.py b/tests/myapp_all/migrations/0001_initial.py
index cddfa82..8d0c21a 100644
--- a/tests/myapp_all/migrations/0001_initial.py
+++ b/tests/myapp_all/migrations/0001_initial.py
@@ -64,7 +64,7 @@ class Migration(migrations.Migration):
                 ('newsbox_title', models.CharField(max_length=255, verbose_name='title')),
                 ('newsbox_slug', models.SlugField(help_text='The part of the title that is used in the URL', verbose_name='slug')),
                 ('newsbox_canonical_url', models.URLField(help_text='Ce champ vous permet d\'indiquer aux moteurs de recherche l\'URL "officielle" d\'un contenu dupliqu\xe9. Si votre contenu provient d\'une autre page (de votre site ou non), alors vous devriez indiquer l\'URL de ce contenu "source" afin d\'\xe9viter que les moteurs de recherches ne vous p\xe9nalisent pour du "contenu dupliqu\xe9". Vous pouvez consultez <a target="_blank" href="http://www.webrankinfo.com/dossiers/techniques/url-canonique">le dossier de webrankinfo</a> \xe0 ce sujet ou <a target="_blank" href="https://support.google.com/webmasters/answer/139066?hl=fr#2">l\'aide google</a>.', null=True, verbose_name='canonical URL', blank=True)),
-                ('master', models.ForeignKey(related_name='translations', editable=False, to='myapp_all.NewsComplete', null=True)),
+                ('master', models.ForeignKey(on_delete=models.CASCADE, related_name='translations', editable=False, to='myapp_all.NewsComplete', null=True)),
             ],
             options={
                 'managed': True,
@@ -109,7 +109,7 @@ class Migration(migrations.Migration):
                 ('newsbox_title', models.CharField(max_length=255, verbose_name='title')),
                 ('newsbox_slug', models.SlugField(help_text='The part of the title that is used in the URL', verbose_name='slug')),
                 ('newsbox_canonical_url', models.URLField(help_text='Ce champ vous permet d\'indiquer aux moteurs de recherche l\'URL "officielle" d\'un contenu dupliqu\xe9. Si votre contenu provient d\'une autre page (de votre site ou non), alors vous devriez indiquer l\'URL de ce contenu "source" afin d\'\xe9viter que les moteurs de recherches ne vous p\xe9nalisent pour du "contenu dupliqu\xe9". Vous pouvez consultez <a target="_blank" href="http://www.webrankinfo.com/dossiers/techniques/url-canonique">le dossier de webrankinfo</a> \xe0 ce sujet ou <a target="_blank" href="https://support.google.com/webmasters/answer/139066?hl=fr#2">l\'aide google</a>.', null=True, verbose_name='canonical URL', blank=True)),
-                ('master', models.ForeignKey(related_name='translations', editable=False, to='myapp_all.NewsExtended', null=True)),
+                ('master', models.ForeignKey(on_delete=models.CASCADE, related_name='translations', editable=False, to='myapp_all.NewsExtended', null=True)),
             ],
             options={
                 'managed': True,
@@ -123,7 +123,7 @@ class Migration(migrations.Migration):
         migrations.CreateModel(
             name='NewsPlugin',
             fields=[
-                ('cmsplugin_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
+                ('cmsplugin_ptr', models.OneToOneField(on_delete=models.CASCADE, parent_link=True, auto_created=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
                 ('title', models.CharField(help_text='Title to display before the list', max_length=255, null=True, verbose_name='Title', blank=True)),
                 ('numitems', models.PositiveSmallIntegerField(default=2, help_text='Number of news to display. "0" allow you to display ALL news', verbose_name='Number of news')),
                 ('with_pager', models.BooleanField(default=False, verbose_name='Display a pager')),
@@ -142,7 +142,7 @@ class Migration(migrations.Migration):
                 ('newsbox_summary', djangocms_text_ckeditor.fields.HTMLField(verbose_name='summary')),
                 ('newsbox_title', models.CharField(max_length=255, verbose_name='title')),
                 ('newsbox_slug', models.SlugField(help_text='The part of the title that is used in the URL', verbose_name='slug')),
-                ('master', models.ForeignKey(related_name='translations', editable=False, to='myapp_all.News', null=True)),
+                ('master', models.ForeignKey(on_delete=models.CASCADE, related_name='translations', editable=False, to='myapp_all.News', null=True)),
             ],
             options={
                 'managed': True,
diff --git a/tests/myapp_all/urls.py b/tests/myapp_all/urls.py
index f07fc59..87fbfa5 100644
--- a/tests/myapp_all/urls.py
+++ b/tests/myapp_all/urls.py
@@ -1,13 +1,13 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.conf.urls import url, include
+from django.urls import include, path
 from django.conf.urls.i18n import i18n_patterns
 from django.contrib import admin
 
 admin.autodiscover()
 
 urlpatterns = i18n_patterns(
-    url(r'^admin/', include(admin.site.urls)),
-    url(r'', include('cms.urls')),
+    path('admin/', include(admin.site.urls)),
+    path('', include('cms.urls')),
 )
diff --git a/tests/myapp_all/urls_news.py b/tests/myapp_all/urls_news.py
index e65edfa..717bbe0 100644
--- a/tests/myapp_all/urls_news.py
+++ b/tests/myapp_all/urls_news.py
@@ -2,13 +2,13 @@
 
 from __future__ import unicode_literals
 
-from django.conf.urls import url
+from django.urls import re_path
 from newsbox_i18n.views import NewsboxI18NDetailView
 
 from .models import News
 
 urlpatterns = [
-    url(
+    re_path(
         r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<slug>[0-9a-zA-Z_-]+)/$',
         NewsboxI18NDetailView.as_view(model=News,),
         name='news_detail'),
diff --git a/tests/myapp_cms/admin.py b/tests/myapp_cms/admin.py
index 1f2a71b..383f684 100644
--- a/tests/myapp_cms/admin.py
+++ b/tests/myapp_cms/admin.py
@@ -8,18 +8,19 @@ from newsbox.admin import NewsboxSEOAdmin, NewsboxExpiredAdmin
 from .models import News, NewsComplete, NewsExtended
 
 
+@admin.register(News)
 class NewsAdmin(NewsboxCMSAdmin):
     pass
 
-admin.site.register(News, NewsAdmin)
 
 
+@admin.register(NewsComplete)
 class NewsCompleteAdmin(NewsboxCMSAdmin, NewsboxSEOAdmin, NewsboxExpiredAdmin):
     pass
 
-admin.site.register(NewsComplete, NewsCompleteAdmin)
 
 
+@admin.register(NewsExtended)
 class NewsExtendedAdmin(NewsboxCMSAdmin, NewsboxSEOAdmin, NewsboxExpiredAdmin):
     def get_fieldsets(self, request, obj=None):
         fieldsets = super(NewsExtendedAdmin, self).get_fieldsets(request, obj)
@@ -33,4 +34,3 @@ class NewsExtendedAdmin(NewsboxCMSAdmin, NewsboxSEOAdmin, NewsboxExpiredAdmin):
         list_display.append('seo_field')
         return list_display
 
-admin.site.register(NewsExtended, NewsExtendedAdmin)
diff --git a/tests/myapp_cms/migrations/0001_initial.py b/tests/myapp_cms/migrations/0001_initial.py
index 32ca514..36d318c 100644
--- a/tests/myapp_cms/migrations/0001_initial.py
+++ b/tests/myapp_cms/migrations/0001_initial.py
@@ -90,7 +90,7 @@ class Migration(migrations.Migration):
         migrations.CreateModel(
             name='NewsPlugin',
             fields=[
-                ('cmsplugin_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
+                ('cmsplugin_ptr', models.OneToOneField(on_delete=models.CASCADE, parent_link=True, auto_created=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
                 ('title', models.CharField(help_text='Title to display before the list', max_length=255, null=True, verbose_name='Title', blank=True)),
                 ('numitems', models.PositiveSmallIntegerField(default=2, help_text='Number of news to display. "0" allow you to display ALL news', verbose_name='Number of news')),
                 ('with_pager', models.BooleanField(default=False, verbose_name='Display a pager')),
diff --git a/tests/myapp_cms/urls.py b/tests/myapp_cms/urls.py
index f723450..7b1e14b 100644
--- a/tests/myapp_cms/urls.py
+++ b/tests/myapp_cms/urls.py
@@ -1,12 +1,12 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.conf.urls import url, include
+from django.urls import include, path
 from django.contrib import admin
 
 admin.autodiscover()
 
 urlpatterns = [
-    url(r'^admin/', include(admin.site.urls)),
-    url(r'', include('cms.urls')),
+    path('admin/', include(admin.site.urls)),
+    path('', include('cms.urls')),
 ]
diff --git a/tests/myapp_cms/urls_news.py b/tests/myapp_cms/urls_news.py
index 689b4be..6abbc26 100644
--- a/tests/myapp_cms/urls_news.py
+++ b/tests/myapp_cms/urls_news.py
@@ -1,13 +1,13 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.conf.urls import url
+from django.urls import re_path
 from newsbox.views import NewsboxDetailView
 
 from .models import News
 
 urlpatterns = [
-    url(
+    re_path(
         r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<slug>[0-9a-zA-Z_-]+)/$',
         NewsboxDetailView.as_view(
             model=News,),
diff --git a/tests/myapp_i18n/migrations/0001_initial.py b/tests/myapp_i18n/migrations/0001_initial.py
index d20f477..119c9e9 100644
--- a/tests/myapp_i18n/migrations/0001_initial.py
+++ b/tests/myapp_i18n/migrations/0001_initial.py
@@ -60,7 +60,7 @@ class Migration(migrations.Migration):
                 ('newsbox_meta_description', models.TextField(max_length=255, null=True, verbose_name='meta description', blank=True)),
                 ('newsbox_meta_keywords', models.CharField(max_length=255, null=True, verbose_name='meta keywords', blank=True)),
                 ('newsbox_canonical_url', models.URLField(help_text='Ce champ vous permet d\'indiquer aux moteurs de recherche l\'URL "officielle" d\'un contenu dupliqu\xe9. Si votre contenu provient d\'une autre page (de votre site ou non), alors vous devriez indiquer l\'URL de ce contenu "source" afin d\'\xe9viter que les moteurs de recherches ne vous p\xe9nalisent pour du "contenu dupliqu\xe9". Vous pouvez consultez <a target="_blank" href="http://www.webrankinfo.com/dossiers/techniques/url-canonique">le dossier de webrankinfo</a> \xe0 ce sujet ou <a target="_blank" href="https://support.google.com/webmasters/answer/139066?hl=fr#2">l\'aide google</a>.', null=True, verbose_name='canonical URL', blank=True)),
-                ('master', models.ForeignKey(related_name='translations', editable=False, to='myapp_i18n.NewsComplete', null=True)),
+                ('master', models.ForeignKey(on_delete=models.CASCADE, related_name='translations', editable=False, to='myapp_i18n.NewsComplete', null=True)),
             ],
             options={
                 'managed': True,
@@ -105,7 +105,7 @@ class Migration(migrations.Migration):
                 ('newsbox_meta_description', models.TextField(max_length=255, null=True, verbose_name='meta description', blank=True)),
                 ('newsbox_meta_keywords', models.CharField(max_length=255, null=True, verbose_name='meta keywords', blank=True)),
                 ('newsbox_canonical_url', models.URLField(help_text='Ce champ vous permet d\'indiquer aux moteurs de recherche l\'URL "officielle" d\'un contenu dupliqu\xe9. Si votre contenu provient d\'une autre page (de votre site ou non), alors vous devriez indiquer l\'URL de ce contenu "source" afin d\'\xe9viter que les moteurs de recherches ne vous p\xe9nalisent pour du "contenu dupliqu\xe9". Vous pouvez consultez <a target="_blank" href="http://www.webrankinfo.com/dossiers/techniques/url-canonique">le dossier de webrankinfo</a> \xe0 ce sujet ou <a target="_blank" href="https://support.google.com/webmasters/answer/139066?hl=fr#2">l\'aide google</a>.', null=True, verbose_name='canonical URL', blank=True)),
-                ('master', models.ForeignKey(related_name='translations', editable=False, to='myapp_i18n.NewsExtended', null=True)),
+                ('master', models.ForeignKey(on_delete=models.CASCADE, related_name='translations', editable=False, to='myapp_i18n.NewsExtended', null=True)),
             ],
             options={
                 'managed': True,
@@ -125,7 +125,7 @@ class Migration(migrations.Migration):
                 ('newsbox_slug', models.SlugField(help_text='The part of the title that is used in the URL', verbose_name='slug')),
                 ('newsbox_summary', models.TextField(verbose_name='summary')),
                 ('newsbox_body', models.TextField(verbose_name='body', blank=True)),
-                ('master', models.ForeignKey(related_name='translations', editable=False, to='myapp_i18n.News', null=True)),
+                ('master', models.ForeignKey(on_delete=models.CASCADE, related_name='translations', editable=False, to='myapp_i18n.News', null=True)),
             ],
             options={
                 'managed': True,
diff --git a/tests/myapp_i18n/urls.py b/tests/myapp_i18n/urls.py
index dd7d886..4f88057 100644
--- a/tests/myapp_i18n/urls.py
+++ b/tests/myapp_i18n/urls.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.conf.urls import url, include
+from django.urls import include, path
 from django.conf.urls.i18n import i18n_patterns
 from django.contrib import admin
 from newsbox.urls import get_urls
@@ -15,4 +15,4 @@ news_urls = get_urls(archive_view={'paginate_by': 1},
                      detail_view=NewsboxI18NDetailView)
 
 admin.autodiscover()
-urlpatterns = [url(r'^admin/', include(admin.site.urls))] + i18n_patterns(*news_urls)
+urlpatterns = [path('admin/', include(admin.site.urls))] + i18n_patterns(*news_urls)
-- 
GitLab