mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 11:04:02 +03:00
Drop all compat support to Django < 2 urls (#7337)
This commit is contained in:
parent
65add6679d
commit
bb795674f8
|
@ -5,65 +5,6 @@ versions of Django/Python, and compatibility wrappers around optional packages.
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
|
||||||
try:
|
|
||||||
from django.urls import ( # noqa
|
|
||||||
URLPattern,
|
|
||||||
URLResolver,
|
|
||||||
)
|
|
||||||
except ImportError:
|
|
||||||
# Will be removed in Django 2.0
|
|
||||||
from django.urls import ( # noqa
|
|
||||||
RegexURLPattern as URLPattern,
|
|
||||||
RegexURLResolver as URLResolver,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_original_route(urlpattern):
|
|
||||||
"""
|
|
||||||
Get the original route/regex that was typed in by the user into the path(), re_path() or url() directive. This
|
|
||||||
is in contrast with get_regex_pattern below, which for RoutePattern returns the raw regex generated from the path().
|
|
||||||
"""
|
|
||||||
if hasattr(urlpattern, 'pattern'):
|
|
||||||
# Django 2.0
|
|
||||||
return str(urlpattern.pattern)
|
|
||||||
else:
|
|
||||||
# Django < 2.0
|
|
||||||
return urlpattern.regex.pattern
|
|
||||||
|
|
||||||
|
|
||||||
def get_regex_pattern(urlpattern):
|
|
||||||
"""
|
|
||||||
Get the raw regex out of the urlpattern's RegexPattern or RoutePattern. This is always a regular expression,
|
|
||||||
unlike get_original_route above.
|
|
||||||
"""
|
|
||||||
if hasattr(urlpattern, 'pattern'):
|
|
||||||
# Django 2.0
|
|
||||||
return urlpattern.pattern.regex.pattern
|
|
||||||
else:
|
|
||||||
# Django < 2.0
|
|
||||||
return urlpattern.regex.pattern
|
|
||||||
|
|
||||||
|
|
||||||
def is_route_pattern(urlpattern):
|
|
||||||
if hasattr(urlpattern, 'pattern'):
|
|
||||||
# Django 2.0
|
|
||||||
from django.urls.resolvers import RoutePattern
|
|
||||||
return isinstance(urlpattern.pattern, RoutePattern)
|
|
||||||
else:
|
|
||||||
# Django < 2.0
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def make_url_resolver(regex, urlpatterns):
|
|
||||||
try:
|
|
||||||
# Django 2.0
|
|
||||||
from django.urls.resolvers import RegexPattern
|
|
||||||
return URLResolver(RegexPattern(regex), urlpatterns)
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
# Django < 2.0
|
|
||||||
return URLResolver(regex, urlpatterns)
|
|
||||||
|
|
||||||
|
|
||||||
def unicode_http_header(value):
|
def unicode_http_header(value):
|
||||||
# Coerce HTTP header value to unicode.
|
# Coerce HTTP header value to unicode.
|
||||||
|
|
|
@ -10,9 +10,9 @@ from django.conf import settings
|
||||||
from django.contrib.admindocs.views import simplify_regex
|
from django.contrib.admindocs.views import simplify_regex
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
|
from django.urls import URLPattern, URLResolver
|
||||||
|
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
from rest_framework.compat import URLPattern, URLResolver, get_original_route
|
|
||||||
from rest_framework.request import clone_request
|
from rest_framework.request import clone_request
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.utils.model_meta import _get_pk
|
from rest_framework.utils.model_meta import _get_pk
|
||||||
|
@ -79,7 +79,7 @@ class EndpointEnumerator:
|
||||||
api_endpoints = []
|
api_endpoints = []
|
||||||
|
|
||||||
for pattern in patterns:
|
for pattern in patterns:
|
||||||
path_regex = prefix + get_original_route(pattern)
|
path_regex = prefix + str(pattern.pattern)
|
||||||
if isinstance(pattern, URLPattern):
|
if isinstance(pattern, URLPattern):
|
||||||
path = self.get_path_from_regex(path_regex)
|
path = self.get_path_from_regex(path_regex)
|
||||||
callback = pattern.callback
|
callback = pattern.callback
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
from django.urls import path, register_converter
|
from django.urls import URLResolver, path, register_converter
|
||||||
|
from django.urls.resolvers import RoutePattern
|
||||||
|
|
||||||
from rest_framework.compat import (
|
|
||||||
URLResolver, get_regex_pattern, is_route_pattern
|
|
||||||
)
|
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +36,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r
|
||||||
for urlpattern in urlpatterns:
|
for urlpattern in urlpatterns:
|
||||||
if isinstance(urlpattern, URLResolver):
|
if isinstance(urlpattern, URLResolver):
|
||||||
# Set of included URL patterns
|
# Set of included URL patterns
|
||||||
regex = get_regex_pattern(urlpattern)
|
regex = urlpattern.pattern.regex.pattern
|
||||||
namespace = urlpattern.namespace
|
namespace = urlpattern.namespace
|
||||||
app_name = urlpattern.app_name
|
app_name = urlpattern.app_name
|
||||||
kwargs = urlpattern.default_kwargs
|
kwargs = urlpattern.default_kwargs
|
||||||
|
@ -49,7 +47,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r
|
||||||
suffix_route)
|
suffix_route)
|
||||||
|
|
||||||
# if the original pattern was a RoutePattern we need to preserve it
|
# if the original pattern was a RoutePattern we need to preserve it
|
||||||
if is_route_pattern(urlpattern):
|
if isinstance(urlpattern.pattern, RoutePattern):
|
||||||
assert path is not None
|
assert path is not None
|
||||||
route = str(urlpattern.pattern)
|
route = str(urlpattern.pattern)
|
||||||
new_pattern = path(route, include((patterns, app_name), namespace), kwargs)
|
new_pattern = path(route, include((patterns, app_name), namespace), kwargs)
|
||||||
|
@ -59,7 +57,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r
|
||||||
ret.append(new_pattern)
|
ret.append(new_pattern)
|
||||||
else:
|
else:
|
||||||
# Regular URL pattern
|
# Regular URL pattern
|
||||||
regex = get_regex_pattern(urlpattern).rstrip('$').rstrip('/') + suffix_pattern
|
regex = urlpattern.pattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern
|
||||||
view = urlpattern.callback
|
view = urlpattern.callback
|
||||||
kwargs = urlpattern.default_args
|
kwargs = urlpattern.default_args
|
||||||
name = urlpattern.name
|
name = urlpattern.name
|
||||||
|
@ -68,7 +66,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r
|
||||||
ret.append(urlpattern)
|
ret.append(urlpattern)
|
||||||
|
|
||||||
# if the original pattern was a RoutePattern we need to preserve it
|
# if the original pattern was a RoutePattern we need to preserve it
|
||||||
if is_route_pattern(urlpattern):
|
if isinstance(urlpattern.pattern, RoutePattern):
|
||||||
assert path is not None
|
assert path is not None
|
||||||
assert suffix_route is not None
|
assert suffix_route is not None
|
||||||
route = str(urlpattern.pattern).rstrip('$').rstrip('/') + suffix_route
|
route = str(urlpattern.pattern).rstrip('$').rstrip('/') + suffix_route
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.urls import path
|
||||||
from rest_framework import (
|
from rest_framework import (
|
||||||
filters, generics, pagination, permissions, serializers
|
filters, generics, pagination, permissions, serializers
|
||||||
)
|
)
|
||||||
from rest_framework.compat import coreapi, coreschema, get_regex_pattern
|
from rest_framework.compat import coreapi, coreschema
|
||||||
from rest_framework.decorators import action, api_view, schema
|
from rest_framework.decorators import action, api_view, schema
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.routers import DefaultRouter, SimpleRouter
|
from rest_framework.routers import DefaultRouter, SimpleRouter
|
||||||
|
@ -1079,7 +1079,7 @@ class SchemaGenerationExclusionTests(TestCase):
|
||||||
inspector = EndpointEnumerator(self.patterns)
|
inspector = EndpointEnumerator(self.patterns)
|
||||||
|
|
||||||
# Not pretty. Mimics internals of EndpointEnumerator to put should_include_endpoint under test
|
# Not pretty. Mimics internals of EndpointEnumerator to put should_include_endpoint under test
|
||||||
pairs = [(inspector.get_path_from_regex(get_regex_pattern(pattern)), pattern.callback)
|
pairs = [(inspector.get_path_from_regex(pattern.pattern.regex.pattern), pattern.callback)
|
||||||
for pattern in self.patterns]
|
for pattern in self.patterns]
|
||||||
|
|
||||||
should_include = [
|
should_include = [
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import datetime
|
import datetime
|
||||||
from importlib import reload as reload_module
|
from importlib import reload as reload_module
|
||||||
|
|
||||||
import django
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -191,7 +190,6 @@ class SearchFilterTests(TestCase):
|
||||||
|
|
||||||
assert terms == ['asdf']
|
assert terms == ['asdf']
|
||||||
|
|
||||||
@pytest.mark.skipif(django.VERSION[:2] < (2, 2), reason="requires django 2.2 or higher")
|
|
||||||
def test_search_field_with_additional_transforms(self):
|
def test_search_field_with_additional_transforms(self):
|
||||||
from django.test.utils import register_lookup
|
from django.test.utils import register_lookup
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ from django.test import TestCase, override_settings
|
||||||
from django.urls import resolve, reverse
|
from django.urls import resolve, reverse
|
||||||
|
|
||||||
from rest_framework import permissions, serializers, viewsets
|
from rest_framework import permissions, serializers, viewsets
|
||||||
from rest_framework.compat import get_regex_pattern
|
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.routers import DefaultRouter, SimpleRouter
|
from rest_framework.routers import DefaultRouter, SimpleRouter
|
||||||
|
@ -192,8 +191,7 @@ class TestCustomLookupFields(URLPatternsTestCase, TestCase):
|
||||||
|
|
||||||
def test_custom_lookup_field_route(self):
|
def test_custom_lookup_field_route(self):
|
||||||
detail_route = notes_router.urls[-1]
|
detail_route = notes_router.urls[-1]
|
||||||
detail_url_pattern = get_regex_pattern(detail_route)
|
assert '<uuid>' in detail_route.pattern.regex.pattern
|
||||||
assert '<uuid>' in detail_url_pattern
|
|
||||||
|
|
||||||
def test_retrieve_lookup_field_list_view(self):
|
def test_retrieve_lookup_field_list_view(self):
|
||||||
response = self.client.get('/example/notes/')
|
response = self.client.get('/example/notes/')
|
||||||
|
@ -229,7 +227,7 @@ class TestLookupValueRegex(TestCase):
|
||||||
def test_urls_limited_by_lookup_value_regex(self):
|
def test_urls_limited_by_lookup_value_regex(self):
|
||||||
expected = ['^notes/$', '^notes/(?P<uuid>[0-9a-f]{32})/$']
|
expected = ['^notes/$', '^notes/(?P<uuid>[0-9a-f]{32})/$']
|
||||||
for idx in range(len(expected)):
|
for idx in range(len(expected)):
|
||||||
assert expected[idx] == get_regex_pattern(self.urls[idx])
|
assert expected[idx] == self.urls[idx].pattern.regex.pattern
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='tests.test_routers')
|
@override_settings(ROOT_URLCONF='tests.test_routers')
|
||||||
|
@ -249,8 +247,7 @@ class TestLookupUrlKwargs(URLPatternsTestCase, TestCase):
|
||||||
|
|
||||||
def test_custom_lookup_url_kwarg_route(self):
|
def test_custom_lookup_url_kwarg_route(self):
|
||||||
detail_route = kwarged_notes_router.urls[-1]
|
detail_route = kwarged_notes_router.urls[-1]
|
||||||
detail_url_pattern = get_regex_pattern(detail_route)
|
assert '^notes/(?P<text>' in detail_route.pattern.regex.pattern
|
||||||
assert '^notes/(?P<text>' in detail_url_pattern
|
|
||||||
|
|
||||||
def test_retrieve_lookup_url_kwarg_detail_view(self):
|
def test_retrieve_lookup_url_kwarg_detail_view(self):
|
||||||
response = self.client.get('/example2/notes/fo/')
|
response = self.client.get('/example2/notes/fo/')
|
||||||
|
@ -273,7 +270,7 @@ class TestTrailingSlashIncluded(TestCase):
|
||||||
def test_urls_have_trailing_slash_by_default(self):
|
def test_urls_have_trailing_slash_by_default(self):
|
||||||
expected = ['^notes/$', '^notes/(?P<pk>[^/.]+)/$']
|
expected = ['^notes/$', '^notes/(?P<pk>[^/.]+)/$']
|
||||||
for idx in range(len(expected)):
|
for idx in range(len(expected)):
|
||||||
assert expected[idx] == get_regex_pattern(self.urls[idx])
|
assert expected[idx] == self.urls[idx].pattern.regex.pattern
|
||||||
|
|
||||||
|
|
||||||
class TestTrailingSlashRemoved(TestCase):
|
class TestTrailingSlashRemoved(TestCase):
|
||||||
|
@ -288,7 +285,7 @@ class TestTrailingSlashRemoved(TestCase):
|
||||||
def test_urls_can_have_trailing_slash_removed(self):
|
def test_urls_can_have_trailing_slash_removed(self):
|
||||||
expected = ['^notes$', '^notes/(?P<pk>[^/.]+)$']
|
expected = ['^notes$', '^notes/(?P<pk>[^/.]+)$']
|
||||||
for idx in range(len(expected)):
|
for idx in range(len(expected)):
|
||||||
assert expected[idx] == get_regex_pattern(self.urls[idx])
|
assert expected[idx] == self.urls[idx].pattern.regex.pattern
|
||||||
|
|
||||||
|
|
||||||
class TestNameableRoot(TestCase):
|
class TestNameableRoot(TestCase):
|
||||||
|
|
|
@ -3,9 +3,9 @@ from collections import namedtuple
|
||||||
|
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import Resolver404, path, re_path
|
from django.urls import Resolver404, URLResolver, path, re_path
|
||||||
|
from django.urls.resolvers import RegexPattern
|
||||||
|
|
||||||
from rest_framework.compat import make_url_resolver
|
|
||||||
from rest_framework.test import APIRequestFactory
|
from rest_framework.test import APIRequestFactory
|
||||||
from rest_framework.urlpatterns import format_suffix_patterns
|
from rest_framework.urlpatterns import format_suffix_patterns
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class FormatSuffixTests(TestCase):
|
||||||
urlpatterns = format_suffix_patterns(urlpatterns, allowed=allowed)
|
urlpatterns = format_suffix_patterns(urlpatterns, allowed=allowed)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.fail("Failed to apply `format_suffix_patterns` on the supplied urlpatterns")
|
self.fail("Failed to apply `format_suffix_patterns` on the supplied urlpatterns")
|
||||||
resolver = make_url_resolver(r'^/', urlpatterns)
|
resolver = URLResolver(RegexPattern(r'^/'), urlpatterns)
|
||||||
for test_path in test_paths:
|
for test_path in test_paths:
|
||||||
try:
|
try:
|
||||||
test_path, expected_resolved = test_path
|
test_path, expected_resolved = test_path
|
||||||
|
|
Loading…
Reference in New Issue
Block a user