Skip to content

Commit

Permalink
Django 42 upgrade changes (#7834)
Browse files Browse the repository at this point in the history
* Django 42 upgrade changes

* Added changelog

* Updated test.yml to exclude django 3.1 and below

* Added readthedocs and pillow pinned=9.5.0

* removed python 3.7 and  added 3.10

* fix: workflow  and django 4.2 compatibility issues

* fix: remove useless

* fix: fix PR errors

* fix: fix typo

* Removed LanguagesessionKEY

* fix: restore 'default_app_config'

* fix: failing tests

* fix: update pip requirement

* fix: failing tests

* updated path from re_path in settingsadmin

* removed unused import

* updated regular expression

* Update settingsadmin.py

---------

Co-authored-by: Josh Peng Yu <joshyu@users.noreply.github.com>
  • Loading branch information
vipulnarang95 and joshyu committed Mar 8, 2024
1 parent 0059b95 commit 16e260b
Show file tree
Hide file tree
Showing 73 changed files with 279 additions and 317 deletions.
20 changes: 7 additions & 13 deletions .github/workflows/test.yml
Expand Up @@ -8,12 +8,10 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ 3.7, 3.8, 3.9 ] # latest release minus two
python-version: [ 3.8, 3.9, '3.10' ] # latest release minus two
requirements-file: [
django-2.2.txt,
django-3.0.txt,
django-3.1.txt,
django-3.2.txt,
django-4.2.txt
]
os: [
ubuntu-20.04,
Expand Down Expand Up @@ -59,20 +57,18 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ 3.7, 3.8, 3.9 ] # latest release minus two
python-version: [ 3.8, 3.9, '3.10' ] # latest release minus two
requirements-file: [
django-2.2.txt,
django-3.0.txt,
django-3.1.txt,
django-3.2.txt,
django-4.2.txt,
]
os: [
ubuntu-20.04,
]

services:
mysql:
image: mysql:5.7
image: mysql:8.0
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: djangocms_test
Expand Down Expand Up @@ -109,12 +105,10 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ 3.7, 3.8, 3.9 ] # latest release minus two
python-version: [ 3.8, 3.9, '3.10' ] # latest release minus two
requirements-file: [
django-2.2.txt,
django-3.0.txt,
django-3.1.txt,
django-3.2.txt,
django-4.2.txt,
]
os: [
ubuntu-20.04,
Expand Down
20 changes: 20 additions & 0 deletions .readthedocs.yaml
@@ -0,0 +1,20 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2

build:
os: ubuntu-22.04
tools:
python: "3.9"

sphinx:
configuration: docs/conf.py
fail_on_warning: false

formats:
- epub
- pdf

python:
install:
- requirements: docs/requirements.txt
4 changes: 4 additions & 0 deletions CHANGELOG.txt
@@ -1,3 +1,7 @@
=== 4.0.1 (unreleased) ===
* Introduced Django 4.2 support.
* Dropped Support for Django<3.1


=== 4.0.0 (unreleased) ===
* feat: Added live-url querystring parameter option for PageContent edit and preview endpoints
Expand Down
7 changes: 2 additions & 5 deletions cms/admin/pageadmin.py
@@ -1,5 +1,4 @@
from collections import namedtuple
import copy
import json

import django
Expand Down Expand Up @@ -88,6 +87,7 @@ def get_site(request):
return site


@admin.register(Page)
class PageAdmin(admin.ModelAdmin):
change_list_template = "admin/cms/page/tree/base.html"
actions_menu_template = 'admin/cms/page/tree/actions_dropdown.html'
Expand Down Expand Up @@ -780,6 +780,7 @@ class Meta:
return render(request, 'admin/cms/page/plugin/change_form.html', context)


@admin.register(PageContent)
class PageContentAdmin(admin.ModelAdmin):
ordering = ('page__node__path',)
search_fields = ('=id', 'page__id', 'page__urls__slug', 'title', 'page__reverse_id')
Expand Down Expand Up @@ -905,8 +906,6 @@ def duplicate(self, request, object_id):
if obj is None:
raise self._get_404_exception(object_id)

request = copy.copy(request)

if request.method == 'GET':
# source is a field in the form
# because its value is in the url,
Expand Down Expand Up @@ -1477,5 +1476,3 @@ def render_page_row(page):
yield render_page_row(page)


admin.site.register(Page, PageAdmin)
admin.site.register(PageContent, PageContentAdmin)
2 changes: 1 addition & 1 deletion cms/admin/placeholderadmin.py
Expand Up @@ -177,6 +177,7 @@ class PlaceholderAdminMixin(metaclass=PlaceholderAdminMixinBase):
pass


@admin.register(Placeholder)
class PlaceholderAdmin(admin.ModelAdmin):

def has_add_permission(self, request):
Expand Down Expand Up @@ -1093,4 +1094,3 @@ def clear_placeholder(self, request, placeholder_id):
return TemplateResponse(request, "admin/cms/page/plugin/delete_confirmation.html", context)


admin.site.register(Placeholder, PlaceholderAdmin)
12 changes: 6 additions & 6 deletions cms/admin/settingsadmin.py
Expand Up @@ -10,7 +10,7 @@
from django.db import transaction
from django.http import HttpResponseRedirect, HttpResponse, HttpResponseBadRequest
from django.http.request import QueryDict
from django.urls import re_path
from django.urls import path
from django.utils.html import conditional_escape
from django.utils.translation import override

Expand All @@ -21,6 +21,7 @@
from cms.utils.urlutils import admin_reverse


@admin.register(UserSettings)
class SettingsAdmin(ModelAdmin):

def get_urls(self):
Expand All @@ -33,16 +34,16 @@ def wrapper(*args, **kwargs):
info = self.model._meta.app_label, self.model._meta.model_name

return [
re_path(r'^session_store/$',
path('session_store/',
self.session_store,
name='%s_%s_session_store' % info),
re_path(r'^cms-toolbar/$',
path('cms-toolbar/',
wrap(self.get_toolbar),
name='%s_%s_get_toolbar' % info),
re_path(r'^$',
path('',
wrap(self.change_view),
name='%s_%s_change' % info),
re_path(r'^(.+)/$',
path('<path:id>/',
wrap(self.change_view),
name='%s_%s_change' % info),
]
Expand Down Expand Up @@ -137,4 +138,3 @@ def get_model_perms(self, request):
return {}


admin.site.register(UserSettings, SettingsAdmin)
2 changes: 1 addition & 1 deletion cms/admin/static_placeholder.py
Expand Up @@ -2,10 +2,10 @@
from django.contrib import admin


@admin.register(StaticPlaceholder)
class StaticPlaceholderAdmin(admin.ModelAdmin):
list_display = ('get_name', 'code', 'site', 'creation_method')
search_fields = ('name', 'code',)
exclude = ('creation_method',)
list_filter = ('creation_method', 'site')

admin.site.register(StaticPlaceholder, StaticPlaceholderAdmin)
2 changes: 1 addition & 1 deletion cms/cms_config.py
@@ -1,5 +1,5 @@
from logging import getLogger
from collections import Iterable
from collections.abc import Iterable

from django.core.exceptions import ImproperlyConfigured

Expand Down
4 changes: 2 additions & 2 deletions cms/cms_plugins.py
Expand Up @@ -8,7 +8,7 @@
from cms.utils.urlutils import admin_reverse
from django.http import HttpResponseForbidden, HttpResponseBadRequest, HttpResponse
from django.middleware.csrf import get_token
from django.urls import re_path
from django.urls import path
from django.utils.translation import gettext, gettext_lazy as _, get_language


Expand Down Expand Up @@ -65,7 +65,7 @@ def get_extra_placeholder_menu_items(cls, request, placeholder):

def get_plugin_urls(self):
return [
re_path(r'^create_alias/$', self.create_alias, name='cms_create_alias'),
path('create_alias/', self.create_alias, name='cms_create_alias'),
]

@classmethod
Expand Down
73 changes: 57 additions & 16 deletions cms/middleware/language.py
@@ -1,22 +1,63 @@
import datetime

from django.utils.translation import LANGUAGE_SESSION_KEY, get_language
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
from django.utils.translation import get_language

from cms.utils.compat import DJANGO_2_2

if DJANGO_2_2:
from django.utils.translation import LANGUAGE_SESSION_KEY


class LanguageCookieMiddleware(MiddlewareMixin):
def process_response(self, request, response):
language = get_language()
if hasattr(request, 'session'):
session_language = request.session.get(LANGUAGE_SESSION_KEY, None)
if session_language and not session_language == language:
request.session[LANGUAGE_SESSION_KEY] = language
request.session.save()
if settings.LANGUAGE_COOKIE_NAME in request.COOKIES and \
request.COOKIES[settings.LANGUAGE_COOKIE_NAME] == language:
def __init__(self, get_response):
super().__init__(get_response)

if DJANGO_2_2:

def __call__(self, request):
response = self.get_response(request)
language = get_language()
if hasattr(request, 'session'):
session_language = request.session.get(LANGUAGE_SESSION_KEY, None)
if session_language and not session_language == language:
request.session[LANGUAGE_SESSION_KEY] = language
request.session.save()
if (
settings.LANGUAGE_COOKIE_NAME in request.COOKIES
and request.COOKIES[settings.LANGUAGE_COOKIE_NAME] == language # noqa: W503
):
return response
response.set_cookie(
settings.LANGUAGE_COOKIE_NAME,
value=language,
domain=settings.LANGUAGE_COOKIE_DOMAIN,
max_age=settings.LANGUAGE_COOKIE_AGE or 365 * 24 * 60 * 60, # 1 year
path=settings.LANGUAGE_COOKIE_PATH,
)
return response
else:

def __call__(self, request):
response = self.get_response(request)
language = get_language()
if (
settings.LANGUAGE_COOKIE_NAME in request.COOKIES # noqa: W503
and request.COOKIES[settings.LANGUAGE_COOKIE_NAME] == language
):
return response

# To ensure support of very old browsers, Django processed automatically "expires" according
# to max_age value.
# https://docs.djangoproject.com/en/3.2/ref/request-response/#django.http.HttpResponse.set_cookie

response.set_cookie(
settings.LANGUAGE_COOKIE_NAME,
value=language,
domain=settings.LANGUAGE_COOKIE_DOMAIN,
max_age=settings.LANGUAGE_COOKIE_AGE or 365 * 24 * 60 * 60, # 1 year
httponly=settings.LANGUAGE_COOKIE_HTTPONLY,
path=settings.LANGUAGE_COOKIE_PATH,
samesite=settings.LANGUAGE_COOKIE_SAMESITE,
secure=settings.LANGUAGE_COOKIE_SECURE,
)
return response
max_age = 365 * 24 * 60 * 60 # 10 years
expires = datetime.datetime.utcnow() + datetime.timedelta(seconds=max_age)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language, expires=expires)
return response
42 changes: 6 additions & 36 deletions cms/signals/__init__.py
Expand Up @@ -13,52 +13,22 @@
#################### Our own signals ###################

# fired after page location is changed - is moved from one node to other
page_moved = Signal(providing_args=["instance"])
page_moved = Signal()

# fired if a public page with an apphook is added or changed
urls_need_reloading = Signal(providing_args=[])
urls_need_reloading = Signal()

# *disclaimer*
# The generic object operation signals are very likely to change
# as their usage evolves.
# As a result, rely on these at your own risk
pre_obj_operation = Signal(
providing_args=[
"operation",
"request",
"token",
"obj",
]
)
pre_obj_operation = Signal()

post_obj_operation = Signal(
providing_args=[
"operation",
"request",
"token",
"obj",
]
)
post_obj_operation = Signal()

pre_placeholder_operation = Signal(
providing_args=[
"operation",
"request",
"language",
"token",
"origin",
]
)
pre_placeholder_operation = Signal()

post_placeholder_operation = Signal(
providing_args=[
"operation",
"request",
"language",
"token",
"origin",
]
)
post_placeholder_operation = Signal()


################### apphook reloading ###################
Expand Down
2 changes: 1 addition & 1 deletion cms/templatetags/cms_tags.py
Expand Up @@ -92,7 +92,7 @@ def _get_page_by_untyped_arg(page_lookup, request, site_id):
middle = BrokenLinkEmailsMiddleware()
domain = request.get_host()
path = request.get_full_path()
referer = force_str(request.META.get('HTTP_REFERER', ''), errors='replace')
referer = force_str(request.headers.get('referer', ''), errors='replace')
if not middle.is_ignorable_request(request, path, domain, referer):
mail_managers(subject, body, fail_silently=True)
return None
Expand Down
3 changes: 2 additions & 1 deletion cms/test_utils/project/cms_urls_for_apphook_tests.py
@@ -1,6 +1,7 @@
from cms.apphook_pool import apphook_pool
from cms.views import details
from django.conf import settings
from django.urls import path
from django.urls import re_path


Expand All @@ -11,7 +12,7 @@

urlpatterns = [
# Public pages
re_path(r'^$', details, {'slug':''}, name='pages-root'),
path('', details, {'slug':''}, name='pages-root'),
reg,
]

Expand Down
4 changes: 2 additions & 2 deletions cms/test_utils/project/customuserapp/models.py
Expand Up @@ -5,7 +5,7 @@
from django.core.mail import send_mail
from django.db import models
from django.utils import timezone
from django.utils.http import urlquote
from urllib.parse import quote
from django.utils.translation import gettext_lazy as _


Expand Down Expand Up @@ -60,7 +60,7 @@ class Meta:
verbose_name_plural = _('users')

def get_absolute_url(self):
return "/users/%s/" % urlquote(self.username)
return "/users/%s/" % quote(self.username)

def get_full_name(self):
"""
Expand Down

0 comments on commit 16e260b

Please sign in to comment.