Skip to content

Commit 23827ed

Browse files
authored
django 4.0 support (#3067)
Add support for django 4.0 Remove references to django.urls.url, this was deprecated in favor of re_path in django 3 and removed in django 4 django 4 release notes djangorestframework version >= 3.13 has support for django 4 compatibility release nodes django_host version >= 5.0 has support for django 4 compatibility release nodes
1 parent 921640e commit 23827ed

File tree

10 files changed

+112
-69
lines changed

10 files changed

+112
-69
lines changed

ddtrace/contrib/django/patch.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ def traced_as_view(django, pin, func, instance, args, kwargs):
435435
except Exception:
436436
log.debug("Failed to instrument Django view %r", instance, exc_info=True)
437437
view = func(*args, **kwargs)
438-
return wrapt.FunctionWrapper(view, traced_func(django, "django.view", resource=func_name(view)))
438+
return wrapt.FunctionWrapper(view, traced_func(django, "django.view", resource=func_name(instance)))
439439

440440

441441
@trace_utils.with_traced_module
@@ -484,7 +484,10 @@ def _patch(django):
484484
# DEV: this check will be replaced with import hooks in the future
485485
if "django.conf.urls.static" not in sys.modules:
486486
import django.conf.urls.static
487-
trace_utils.wrap(django, "conf.urls.url", traced_urls_path(django))
487+
488+
if django.VERSION < (4, 0, 0):
489+
trace_utils.wrap(django, "conf.urls.url", traced_urls_path(django))
490+
488491
if django.VERSION >= (2, 0, 0):
489492
trace_utils.wrap(django, "urls.path", traced_urls_path(django))
490493
trace_utils.wrap(django, "urls.re_path", traced_urls_path(django))

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ contacting support.
7070
+--------------------------------------------------+---------------+----------------+
7171
| :ref:`consul` | >= 0.7 | Yes [3]_ |
7272
+--------------------------------------------------+---------------+----------------+
73-
| :ref:`django` | >= 1.8, <4.0 | Yes |
73+
| :ref:`django` | >= 1.8 | Yes |
7474
+--------------------------------------------------+---------------+----------------+
7575
| :ref:`djangorestframework <djangorestframework>` | >= 3.4 | No |
7676
+--------------------------------------------------+---------------+----------------+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
features:
3+
- |
4+
Add django 4.0 support.

riotfile.py

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -523,23 +523,21 @@ def select_pys(min_version=MIN_PYTHON_VERSION, max_version=MAX_PYTHON_VERSION):
523523
],
524524
},
525525
),
526-
# TODO: Add support for Django 4.0 in tests
527-
# Venv(
528-
# pys=select_pys(min_version="3.8"),
529-
# pkgs={
530-
# "django": [
531-
# "~=4.0.0",
532-
# latest,
533-
# ],
534-
# },
535-
# ),
526+
Venv(
527+
pys=select_pys(min_version="3.8"),
528+
pkgs={
529+
"django": [
530+
"~=4.0.0",
531+
latest,
532+
],
533+
},
534+
),
536535
],
537536
),
538537
Venv(
539538
name="django_hosts",
540539
command="pytest {cmdargs} tests/contrib/django_hosts",
541540
pkgs={
542-
"django_hosts": ["~=4.0", latest],
543541
"pytest-django": [
544542
"==3.10.0",
545543
],
@@ -548,28 +546,27 @@ def select_pys(min_version=MIN_PYTHON_VERSION, max_version=MAX_PYTHON_VERSION):
548546
Venv(
549547
pys=["3.5"],
550548
pkgs={
549+
"django_hosts": ["~=4.0"],
551550
"django": ["~=2.2"],
552551
},
553552
),
554553
Venv(
555554
pys=select_pys(min_version="3.6"),
556555
pkgs={
556+
"django_hosts": ["~=4.0"],
557557
"django": [
558558
"~=2.2",
559559
"~=3.2",
560560
],
561561
},
562562
),
563-
# TODO: Add support for Django 4.0 in tests
564-
# Venv(
565-
# pys=select_pys(min_version="3.8"),
566-
# pkgs={
567-
# "django": [
568-
# "~=4.0",
569-
# latest,
570-
# ],
571-
# },
572-
# ),
563+
Venv(
564+
pys=select_pys(min_version="3.8"),
565+
pkgs={
566+
"django_hosts": ["~=5.0", latest],
567+
"django": "~=4.0",
568+
},
569+
),
573570
],
574571
),
575572
Venv(
@@ -608,15 +605,14 @@ def select_pys(min_version=MIN_PYTHON_VERSION, max_version=MAX_PYTHON_VERSION):
608605
"pytest-django": "==3.10.0",
609606
},
610607
),
611-
# TODO: Add support for Django 4.0 in tests
612-
# Venv(
613-
# pys=select_pys(min_version="3.8"),
614-
# pkgs={
615-
# "django": latest,
616-
# "djangorestframework": ">=3.11,<3.12",
617-
# "pytest-django": "==3.10.0",
618-
# },
619-
# ),
608+
Venv(
609+
pys=select_pys(min_version="3.8"),
610+
pkgs={
611+
"django": "~=4.0",
612+
"djangorestframework": ["~=3.13", latest],
613+
"pytest-django": "==3.10.0",
614+
},
615+
),
620616
],
621617
),
622618
Venv(
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
from django.conf.urls import url
1+
import django
22
from django.http import HttpResponse
33

44

5+
# django.conf.urls.url was deprecated in django 3 and removed in django 4
6+
if django.VERSION < (4, 0, 0):
7+
from django.conf.urls import url as handler
8+
else:
9+
from django.urls import re_path as handler
10+
11+
512
def include_view(request):
613
return HttpResponse(status=200)
714

815

916
urlpatterns = [
10-
url("test/", include_view),
17+
handler("test/", include_view),
1118
]

tests/contrib/django/django_app/settings.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import os
22

3+
import django
4+
35
from ddtrace import tracer
46
from tests.webclient import PingFilter
57

@@ -30,13 +32,18 @@
3032
},
3133
}
3234

35+
django_cache = "django_redis.cache.RedisCache"
36+
if django.VERSION >= (4, 0, 0):
37+
django_cache = "django.core.cache.backends.redis.RedisCache"
38+
39+
3340
CACHES = {
3441
"default": {
3542
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
3643
"LOCATION": "unique-snowflake",
3744
},
3845
"redis": {
39-
"BACKEND": "django_redis.cache.RedisCache",
46+
"BACKEND": django_cache,
4047
"LOCATION": "redis://127.0.0.1:6379/1",
4148
},
4249
"pylibmc": {

tests/contrib/django/django_app/urls.py

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from django.conf.urls import url
1+
import django
22
from django.contrib.auth import login
33
from django.contrib.auth.models import User
44
from django.http import HttpResponse
@@ -13,6 +13,13 @@
1313
from .. import views
1414

1515

16+
# django.conf.urls.url was deprecated in django 3 and removed in django 4
17+
if django.VERSION < (4, 0, 0):
18+
from django.conf.urls import url as handler
19+
else:
20+
from django.urls import re_path as handler
21+
22+
1623
def repath_view(request):
1724
return HttpResponse(status=200)
1825

@@ -41,32 +48,32 @@ def shutdown(request):
4148

4249

4350
urlpatterns = [
44-
url(r"^$", views.index),
45-
url(r"^simple/$", views.BasicView.as_view()),
46-
url(r"^users/$", views.UserList.as_view(), name="users-list"),
47-
url(r"^cached-template/$", views.TemplateCachedUserList.as_view(), name="cached-template-list"),
48-
url(r"^safe-template/$", views.SafeTemplateUserList.as_view(), name="safe-template-list"),
49-
url(r"^cached-users/$", cache_page(60)(views.UserList.as_view()), name="cached-users-list"),
50-
url(r"^fail-view/$", views.ForbiddenView.as_view(), name="forbidden-view"),
51-
url(r"^authenticated/$", authenticated_view, name="authenticated-view"),
52-
url(r"^static-method-view/$", views.StaticMethodView.as_view(), name="static-method-view"),
53-
url(r"^fn-view/$", views.function_view, name="fn-view"),
54-
url(r"^feed-view/$", views.FeedView(), name="feed-view"),
55-
url(r"^partial-view/$", views.partial_view, name="partial-view"),
56-
url(r"^lambda-view/$", views.lambda_view, name="lambda-view"),
57-
url(r"^error-500/$", views.error_500, name="error-500"),
58-
url(r"^template-view/$", views.template_view, name="template-view"),
59-
url(r"^template-simple-view/$", views.template_simple_view, name="template-simple-view"),
60-
url(r"^template-list-view/$", views.template_list_view, name="template-list-view"),
51+
handler(r"^$", views.index),
52+
handler(r"^simple/$", views.BasicView.as_view()),
53+
handler(r"^users/$", views.UserList.as_view(), name="users-list"),
54+
handler(r"^cached-template/$", views.TemplateCachedUserList.as_view(), name="cached-template-list"),
55+
handler(r"^safe-template/$", views.SafeTemplateUserList.as_view(), name="safe-template-list"),
56+
handler(r"^cached-users/$", cache_page(60)(views.UserList.as_view()), name="cached-users-list"),
57+
handler(r"^fail-view/$", views.ForbiddenView.as_view(), name="forbidden-view"),
58+
handler(r"^authenticated/$", authenticated_view, name="authenticated-view"),
59+
handler(r"^static-method-view/$", views.StaticMethodView.as_view(), name="static-method-view"),
60+
handler(r"^fn-view/$", views.function_view, name="fn-view"),
61+
handler(r"^feed-view/$", views.FeedView(), name="feed-view"),
62+
handler(r"^partial-view/$", views.partial_view, name="partial-view"),
63+
handler(r"^lambda-view/$", views.lambda_view, name="lambda-view"),
64+
handler(r"^error-500/$", views.error_500, name="error-500"),
65+
handler(r"^template-view/$", views.template_view, name="template-view"),
66+
handler(r"^template-simple-view/$", views.template_simple_view, name="template-simple-view"),
67+
handler(r"^template-list-view/$", views.template_list_view, name="template-list-view"),
6168
re_path(r"re-path.*/", repath_view),
6269
path("path/", path_view),
6370
path("include/", include("tests.contrib.django.django_app.extra_urls")),
6471
# This must precede composed-view.
65-
url(r"^some-static-view/$", TemplateView.as_view(template_name="my-template.html")),
66-
url(r"^composed-template-view/$", views.ComposedTemplateView.as_view(), name="composed-template-view"),
67-
url(r"^composed-get-view/$", views.ComposedGetView.as_view(), name="composed-get-view"),
68-
url(r"^composed-view/$", views.ComposedView.as_view(), name="composed-view"),
69-
url(r"^404-view/$", views.not_found_view, name="404-view"),
70-
url(r"^shutdown-tracer/$", shutdown, name="shutdown-tracer"),
71-
url(r"^alter-resource/$", views.alter_resource),
72+
handler(r"^some-static-view/$", TemplateView.as_view(template_name="my-template.html")),
73+
handler(r"^composed-template-view/$", views.ComposedTemplateView.as_view(), name="composed-template-view"),
74+
handler(r"^composed-get-view/$", views.ComposedGetView.as_view(), name="composed-get-view"),
75+
handler(r"^composed-view/$", views.ComposedView.as_view(), name="composed-view"),
76+
handler(r"^404-view/$", views.not_found_view, name="404-view"),
77+
handler(r"^shutdown-tracer/$", shutdown, name="shutdown-tracer"),
78+
handler(r"^alter-resource/$", views.alter_resource),
7279
]
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
from django.conf.urls import url
1+
import django
22

33
from .. import views
44

55

6+
if django.VERSION < (4, 0, 0):
7+
from django.conf.urls import url as handler
8+
else:
9+
from django.urls import re_path as handler
10+
11+
612
urlpatterns = [
7-
url(r"^$", views.index),
8-
url(r"^simple/$", views.BasicView.as_view()),
13+
handler(r"^$", views.index),
14+
handler(r"^simple/$", views.BasicView.as_view()),
915
]
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
from django.conf.urls import url
1+
import django
22
from django.http import HttpResponse
33

44

5+
if django.VERSION < (4, 0, 0):
6+
from django.conf.urls import url as handler
7+
else:
8+
from django.urls import re_path as handler
9+
10+
511
def include_view(request):
612
return HttpResponse(status=200)
713

814

915
urlpatterns = [
10-
url("test/", include_view),
16+
handler("test/", include_view),
1117
]

tests/contrib/djangorestframework/app/views.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
import django
12
from django.conf.urls import include
2-
from django.conf.urls import url
33
from django.contrib.auth.models import User
44
from rest_framework import routers
55
from rest_framework import serializers
66
from rest_framework import viewsets
77

88

9+
# django.conf.urls.url was deprecated in django 3 and removed in django 4
10+
if django.VERSION < (4, 0, 0):
11+
from django.conf.urls import url as handler
12+
else:
13+
from django.urls import re_path as handler
14+
15+
916
class UserSerializer(serializers.HyperlinkedModelSerializer):
1017
class Meta:
1118
model = User
@@ -27,6 +34,6 @@ class UserViewSet(viewsets.ModelViewSet):
2734
# Wire up our API using automatic URL routing.
2835
# Additionally, we include login URLs for the browsable API.
2936
urlpatterns = [
30-
url(r"^", include(router.urls)),
31-
url(r"^api-auth/", include("rest_framework.urls", namespace="rest_framework")),
37+
handler(r"^", include(router.urls)),
38+
handler(r"^api-auth/", include("rest_framework.urls", namespace="rest_framework")),
3239
]

0 commit comments

Comments
 (0)