mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 07:57:55 +03:00 
			
		
		
		
	Merge branch '39/release' of https://github.com/carltongibson/django-rest-framework into carltongibson-39/release
This commit is contained in:
		
						commit
						f99a87e5e6
					
				
							
								
								
									
										108
									
								
								docs/community/3.9-announcement.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								docs/community/3.9-announcement.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,108 @@ | |||
| <style> | ||||
| .promo li a { | ||||
|     float: left; | ||||
|     width: 130px; | ||||
|     height: 20px; | ||||
|     text-align: center; | ||||
|     margin: 10px 30px; | ||||
|     padding: 150px 0 0 0; | ||||
|     background-position: 0 50%; | ||||
|     background-size: 130px auto; | ||||
|     background-repeat: no-repeat; | ||||
|     font-size: 120%; | ||||
|     color: black; | ||||
| } | ||||
| .promo li { | ||||
|     list-style: none; | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
| # Django REST framework 3.9 | ||||
| 
 | ||||
| The 3.9 release gives access to _extra actions_ in the Browsable API, introduces composable permissions and built-in [OpenAPI][openapi] schema support. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## Funding | ||||
| 
 | ||||
| If you use REST framework commercially and would like to see this work continue, we strongly encourage you to invest in its continued development by | ||||
| **[signing up for a paid plan][funding]**. | ||||
| 
 | ||||
| 
 | ||||
| TODO: UPDATE SPONSORS. | ||||
| 
 | ||||
| *We'd like to say thanks in particular our premium backers, [Rover](http://jobs.rover.com/), [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), [Machinalis](https://hello.machinalis.co.uk/), and [Rollbar](https://rollbar.com).* | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## ViewSet _Extra Actions_ available in the Browsable API | ||||
| 
 | ||||
| Following the introduction of the `action` decorator in v3.8, _extra actions_ defined on a ViewSet are now available | ||||
| from the Browsable API. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| When defined, a dropdown of "Extra Actions", appropriately filtered to detail/non-detail actions, is displayed. | ||||
| 
 | ||||
| ## In-built OpenAPI schema support | ||||
| 
 | ||||
| TODO | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## Deprecations | ||||
| 
 | ||||
| ### `DjangoObjectPermissionsFilter` moved to third-party package. | ||||
| 
 | ||||
| The `DjangoObjectPermissionsFilter` class is pending deprecation, will be deprecated in 3.10 and removed entirely in 3.11. | ||||
| 
 | ||||
| It has been moved to the third-party [`djangorestframework-guardian`](https://github.com/rpkilby/django-rest-framework-guardian) | ||||
| package. Please use this instead. | ||||
| 
 | ||||
| ### Router argument/method renamed to use `basename` for consistency. | ||||
| 
 | ||||
| * The `Router.register` `base_name` argument has been renamed in favor of `basename`. | ||||
| * The `Router.get_default_base_name` method has been renamed in favor of `Router.get_default_basename`. [#5990][gh5990] | ||||
| 
 | ||||
| See [#5990][gh5990]. | ||||
| 
 | ||||
| [gh5990]: https://github.com/encode/django-rest-framework/pull/5990 | ||||
| 
 | ||||
| `base_name` and `get_default_base_name()` are pending deprecation. They will be deprecated in 3.10 and removed entirely in 3.11. | ||||
| 
 | ||||
| ### `action` decorator replaces `list_route` and `detail_route` | ||||
| 
 | ||||
| Both `list_route` and `detail_route` are now deprecated in favour of the single `action` decorator. | ||||
| They will be removed entirely in 3.10. | ||||
| 
 | ||||
| The `action` decorator takes a boolean `detail` argument. | ||||
| 
 | ||||
| * Replace `detail_route` uses with `@action(detail=True)`. | ||||
| * Replace `list_route` uses with `@action(detail=False)`. | ||||
| 
 | ||||
| ### `exclude_from_schema` | ||||
| 
 | ||||
| Both `APIView.exclude_from_schema` and the `exclude_from_schema` argument to the `@api_view` have now been removed. | ||||
| 
 | ||||
| For `APIView` you should instead set a `schema = None` attribute on the view class. | ||||
| 
 | ||||
| For function based views the `@schema` decorator can be used to exclude the view from the schema, by using `@schema(None)`. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ## Minor fixes and improvements | ||||
| 
 | ||||
| There are a large number of minor fixes and improvements in this release. See the [release notes](release-notes.md) page | ||||
| for a complete listing. | ||||
| 
 | ||||
| 
 | ||||
| ## What's next | ||||
| 
 | ||||
| 
 | ||||
| TODO... | ||||
| 
 | ||||
| 
 | ||||
| [funding]: funding.md | ||||
| [gh5886]: https://github.com/encode/django-rest-framework/issues/5886 | ||||
| [gh5705]: https://github.com/encode/django-rest-framework/issues/5705 | ||||
| [openapi]: https://www.openapis.org/ | ||||
|  | @ -42,11 +42,52 @@ You can determine your currently installed version using `pip show`: | |||
| 
 | ||||
| ### 3.9.0 | ||||
| 
 | ||||
| **Date**: Unreleased | ||||
| **Date**: [1st October 2018][3.9.0-milestone] | ||||
| 
 | ||||
| * Improvements to ViewSet extra actions [#5605][gh5605] | ||||
| * Fix `action` support for ViewSet suffixes [#6081][gh6081] | ||||
| * Allow `action` docs sections [#6060][gh6060] | ||||
| * Deprecate the `Router.register` `base_name` argument in favor of `basename`. [#5990][gh5990] | ||||
| * Deprecate the `Router.get_default_base_name` method in favor of `Router.get_default_basename`. [#5990][gh5990] | ||||
| * Change `CharField` to disallow null bytes. [#6073][gh6073] | ||||
|   To revert to the old behavior, subclass `CharField` and remove `ProhibitNullCharactersValidator` from the validators. | ||||
|   ```python | ||||
|   class NullableCharField(serializers.CharField): | ||||
|       def __init__(self, *args, **kwargs): | ||||
|           super().__init__(*args, **kwargs) | ||||
|           self.validators = [v for v in self.validators if not isinstance(v, ProhibitNullCharactersValidator)] | ||||
|   ``` | ||||
| * Add `OpenAPIRenderer` and `generate_schema` management command. [#6229][gh6229] | ||||
| * Add OpenAPIRenderer by default, and add schema docs. [#6233][gh6233] | ||||
| * Allow permissions to be composed [#5753][gh5753] | ||||
| * Allow nullable BooleanField in Django 2.1 [#6183][gh6183] | ||||
| * Add testing of Python 3.7 support [#6141][gh6141] | ||||
| * Test using Django 2.1 final release. [#6109][gh6109] | ||||
| * Added djangorestframework-datatables to third-party packages [#5931][gh5931] | ||||
| * Change ISO 8601 date format to exclude year/month [#5936][gh5936] | ||||
| * Update all pypi.python.org URLs to pypi.org [#5942][gh5942] | ||||
| * Ensure that html forms (multipart form data) respect optional fields [#5927][gh5927] | ||||
| * Allow hashing of ErrorDetail. [#5932][gh5932] | ||||
| * Correct schema parsing for JSONField [#5878][gh5878] | ||||
| * Render descriptions (from help_text) using safe [#5869][gh5869] | ||||
| * Removed input value from deault_error_message [#5881][gh5881] | ||||
| * Added min_value/max_value support in DurationField [#5643][gh5643] | ||||
| * Fixed instance being overwritten in pk-only optimization try/except block [#5747][gh5747] | ||||
| * Fixed AttributeError from items filter when value is None [#5981][gh5981] | ||||
| * Fixed Javascript `e.indexOf` is not a function error [#5982][gh5982] | ||||
| * Fix schemas for extra actions [#5992][gh5992] | ||||
| * Improved get_error_detail to use error_dict/error_list [#5785][gh5785] | ||||
| * Imprvied URLs in Admin renderer [#5988][gh5988] | ||||
| * Add "Community" section to docs, minor cleanup [#5993][gh5993] | ||||
| * Moved guardian imports out of compat [#6054][gh6054] | ||||
| * Deprecate the `DjangoObjectPermissionsFilter` class, moved to the `djangorestframework-guardian` package. [#6075][gh6075] | ||||
| * Drop Django 1.10 support [#5657][gh5657] | ||||
| * Only catch TypeError/ValueError for object lookups [#6028][gh6028] | ||||
| * Handle models without .objects manager in ModelSerializer. [#6111][gh6111] | ||||
| * Improve ModelSerializer.create() error message. [#6112][gh6112] | ||||
| * Fix CSRF cookie check failure when using session auth with django 1.11.6+ [#6113][gh6113] | ||||
| * Updated JWT docs. [#6138][gh6138] | ||||
| * Fix autoescape not getting passed to urlize_quoted_links filter [#6191][gh6191] | ||||
| 
 | ||||
| 
 | ||||
| ## 3.8.x series | ||||
|  | @ -1093,6 +1134,7 @@ For older release notes, [please see the version 2.x documentation][old-release- | |||
| [3.8.0-milestone]: https://github.com/encode/django-rest-framework/milestone/61?closed=1 | ||||
| [3.8.1-milestone]: https://github.com/encode/django-rest-framework/milestone/67?closed=1 | ||||
| [3.8.2-milestone]: https://github.com/encode/django-rest-framework/milestone/68?closed=1 | ||||
| [3.9.0-milestone]: https://github.com/encode/django-rest-framework/milestone/66?closed=1 | ||||
| 
 | ||||
| <!-- 3.0.1 --> | ||||
| [gh2013]: https://github.com/encode/django-rest-framework/issues/2013 | ||||
|  | @ -1974,5 +2016,39 @@ For older release notes, [please see the version 2.x documentation][old-release- | |||
| [gh5920]: https://github.com/encode/django-rest-framework/issues/5920 | ||||
| 
 | ||||
| <!-- 3.9.0 --> | ||||
| [gh6109]: https://github.com/encode/django-rest-framework/issues/6109 | ||||
| [gh6141]: https://github.com/encode/django-rest-framework/issues/6141 | ||||
| [gh6113]: https://github.com/encode/django-rest-framework/issues/6113 | ||||
| [gh6112]: https://github.com/encode/django-rest-framework/issues/6112 | ||||
| [gh6111]: https://github.com/encode/django-rest-framework/issues/6111 | ||||
| [gh6028]: https://github.com/encode/django-rest-framework/issues/6028 | ||||
| [gh5657]: https://github.com/encode/django-rest-framework/issues/5657 | ||||
| [gh6054]: https://github.com/encode/django-rest-framework/issues/6054 | ||||
| [gh5993]: https://github.com/encode/django-rest-framework/issues/5993 | ||||
| [gh5990]: https://github.com/encode/django-rest-framework/issues/5990 | ||||
| [gh5988]: https://github.com/encode/django-rest-framework/issues/5988 | ||||
| [gh5785]: https://github.com/encode/django-rest-framework/issues/5785 | ||||
| [gh5992]: https://github.com/encode/django-rest-framework/issues/5992 | ||||
| [gh5605]: https://github.com/encode/django-rest-framework/issues/5605 | ||||
| [gh5982]: https://github.com/encode/django-rest-framework/issues/5982 | ||||
| [gh5981]: https://github.com/encode/django-rest-framework/issues/5981 | ||||
| [gh5747]: https://github.com/encode/django-rest-framework/issues/5747 | ||||
| [gh5643]: https://github.com/encode/django-rest-framework/issues/5643 | ||||
| [gh5881]: https://github.com/encode/django-rest-framework/issues/5881 | ||||
| [gh5869]: https://github.com/encode/django-rest-framework/issues/5869 | ||||
| [gh5878]: https://github.com/encode/django-rest-framework/issues/5878 | ||||
| [gh5932]: https://github.com/encode/django-rest-framework/issues/5932 | ||||
| [gh5927]: https://github.com/encode/django-rest-framework/issues/5927 | ||||
| [gh5942]: https://github.com/encode/django-rest-framework/issues/5942 | ||||
| [gh5936]: https://github.com/encode/django-rest-framework/issues/5936 | ||||
| [gh5931]: https://github.com/encode/django-rest-framework/issues/5931 | ||||
| [gh6183]: https://github.com/encode/django-rest-framework/issues/6183 | ||||
| [gh6075]: https://github.com/encode/django-rest-framework/issues/6075 | ||||
| [gh6138]: https://github.com/encode/django-rest-framework/issues/6138 | ||||
| [gh6081]: https://github.com/encode/django-rest-framework/issues/6081 | ||||
| [gh6073]: https://github.com/encode/django-rest-framework/issues/6073 | ||||
| [gh6191]: https://github.com/encode/django-rest-framework/issues/6191 | ||||
| [gh6060]: https://github.com/encode/django-rest-framework/issues/6060 | ||||
| [gh6233]: https://github.com/encode/django-rest-framework/issues/6233 | ||||
| [gh5753]: https://github.com/encode/django-rest-framework/issues/5753 | ||||
| [gh6229]: https://github.com/encode/django-rest-framework/issues/6229 | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ ______ _____ _____ _____    __ | |||
| """ | ||||
| 
 | ||||
| __title__ = 'Django REST framework' | ||||
| __version__ = '3.8.2' | ||||
| __version__ = '3.9.0' | ||||
| __author__ = 'Tom Christie' | ||||
| __license__ = 'BSD 2-Clause' | ||||
| __copyright__ = 'Copyright 2011-2018 Tom Christie' | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ from django.utils import six | |||
| from rest_framework.views import APIView | ||||
| 
 | ||||
| 
 | ||||
| def api_view(http_method_names=None, exclude_from_schema=False): | ||||
| def api_view(http_method_names=None): | ||||
|     """ | ||||
|     Decorator that converts a function-based view into an APIView subclass. | ||||
|     Takes a list of allowed methods for the view as an argument. | ||||
|  | @ -77,15 +77,8 @@ def api_view(http_method_names=None, exclude_from_schema=False): | |||
|         WrappedAPIView.schema = getattr(func, 'schema', | ||||
|                                         APIView.schema) | ||||
| 
 | ||||
|         if exclude_from_schema: | ||||
|             warnings.warn( | ||||
|                 "The `exclude_from_schema` argument to `api_view` is deprecated. " | ||||
|                 "Use the `schema` decorator instead, passing `None`.", | ||||
|                 DeprecationWarning | ||||
|             ) | ||||
|             WrappedAPIView.exclude_from_schema = exclude_from_schema | ||||
| 
 | ||||
|         return WrappedAPIView.as_view() | ||||
| 
 | ||||
|     return decorator | ||||
| 
 | ||||
| 
 | ||||
|  | @ -230,9 +223,9 @@ def detail_route(methods=None, **kwargs): | |||
|     Used to mark a method on a ViewSet that should be routed for detail requests. | ||||
|     """ | ||||
|     warnings.warn( | ||||
|         "`detail_route` is pending deprecation and will be removed in 3.10 in favor of " | ||||
|         "`detail_route` is deprecated and will be removed in 3.10 in favor of " | ||||
|         "`action`, which accepts a `detail` bool. Use `@action(detail=True)` instead.", | ||||
|         PendingDeprecationWarning, stacklevel=2 | ||||
|         DeprecationWarning, stacklevel=2 | ||||
|     ) | ||||
| 
 | ||||
|     def decorator(func): | ||||
|  | @ -248,9 +241,9 @@ def list_route(methods=None, **kwargs): | |||
|     Used to mark a method on a ViewSet that should be routed for list requests. | ||||
|     """ | ||||
|     warnings.warn( | ||||
|         "`list_route` is pending deprecation and will be removed in 3.10 in favor of " | ||||
|         "`list_route` is deprecated and will be removed in 3.10 in favor of " | ||||
|         "`action`, which accepts a `detail` bool. Use `@action(detail=False)` instead.", | ||||
|         PendingDeprecationWarning, stacklevel=2 | ||||
|         DeprecationWarning, stacklevel=2 | ||||
|     ) | ||||
| 
 | ||||
|     def decorator(func): | ||||
|  |  | |||
|  | @ -40,10 +40,10 @@ DynamicRoute = namedtuple('DynamicRoute', ['url', 'name', 'detail', 'initkwargs' | |||
| class DynamicDetailRoute(object): | ||||
|     def __new__(cls, url, name, initkwargs): | ||||
|         warnings.warn( | ||||
|             "`DynamicDetailRoute` is pending deprecation and will be removed in 3.10 " | ||||
|             "`DynamicDetailRoute` is deprecated and will be removed in 3.10 " | ||||
|             "in favor of `DynamicRoute`, which accepts a `detail` boolean. Use " | ||||
|             "`DynamicRoute(url, name, True, initkwargs)` instead.", | ||||
|             PendingDeprecationWarning, stacklevel=2 | ||||
|             DeprecationWarning, stacklevel=2 | ||||
|         ) | ||||
|         return DynamicRoute(url, name, True, initkwargs) | ||||
| 
 | ||||
|  | @ -51,10 +51,10 @@ class DynamicDetailRoute(object): | |||
| class DynamicListRoute(object): | ||||
|     def __new__(cls, url, name, initkwargs): | ||||
|         warnings.warn( | ||||
|             "`DynamicListRoute` is pending deprecation and will be removed in 3.10 in " | ||||
|             "`DynamicListRoute` is deprecated and will be removed in 3.10 in " | ||||
|             "favor of `DynamicRoute`, which accepts a `detail` boolean. Use " | ||||
|             "`DynamicRoute(url, name, False, initkwargs)` instead.", | ||||
|             PendingDeprecationWarning, stacklevel=2 | ||||
|             DeprecationWarning, stacklevel=2 | ||||
|         ) | ||||
|         return DynamicRoute(url, name, False, initkwargs) | ||||
| 
 | ||||
|  | @ -77,7 +77,7 @@ def flatten(list_of_lists): | |||
| 
 | ||||
| class RenameRouterMethods(RenameMethodsBase): | ||||
|     renamed_methods = ( | ||||
|         ('get_default_base_name', 'get_default_basename', DeprecationWarning), | ||||
|         ('get_default_base_name', 'get_default_basename', PendingDeprecationWarning), | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -87,8 +87,8 @@ class BaseRouter(six.with_metaclass(RenameRouterMethods)): | |||
| 
 | ||||
|     def register(self, prefix, viewset, basename=None, base_name=None): | ||||
|         if base_name is not None: | ||||
|             msg = "The `base_name` argument has been deprecated in favor of `basename`." | ||||
|             warnings.warn(msg, DeprecationWarning, 2) | ||||
|             msg = "The `base_name` argument is pending deprecation in favor of `basename`." | ||||
|             warnings.warn(msg, PendingDeprecationWarning, 2) | ||||
| 
 | ||||
|         assert not (basename and base_name), ( | ||||
|             "Do not provide both the `basename` and `base_name` arguments.") | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ generators.py   # Top-down schema generation | |||
| See schemas.__init__.py for package overview. | ||||
| """ | ||||
| import re | ||||
| import warnings | ||||
| from collections import Counter, OrderedDict | ||||
| from importlib import import_module | ||||
| 
 | ||||
|  | @ -207,14 +206,6 @@ class EndpointEnumerator(object): | |||
|         if not is_api_view(callback): | ||||
|             return False  # Ignore anything except REST framework views. | ||||
| 
 | ||||
|         if hasattr(callback.cls, 'exclude_from_schema'): | ||||
|             fmt = ("The `{}.exclude_from_schema` attribute is deprecated. " | ||||
|                    "Set `schema = None` instead.") | ||||
|             msg = fmt.format(callback.cls.__name__) | ||||
|             warnings.warn(msg, DeprecationWarning) | ||||
|             if getattr(callback.cls, 'exclude_from_schema', False): | ||||
|                 return False | ||||
| 
 | ||||
|         if callback.cls.schema is None: | ||||
|             return False | ||||
| 
 | ||||
|  |  | |||
|  | @ -290,34 +290,34 @@ class ActionDecoratorTestCase(TestCase): | |||
|                 raise NotImplementedError | ||||
| 
 | ||||
|     def test_detail_route_deprecation(self): | ||||
|         with pytest.warns(PendingDeprecationWarning) as record: | ||||
|         with pytest.warns(DeprecationWarning) as record: | ||||
|             @detail_route() | ||||
|             def view(request): | ||||
|                 raise NotImplementedError | ||||
| 
 | ||||
|         assert len(record) == 1 | ||||
|         assert str(record[0].message) == ( | ||||
|             "`detail_route` is pending deprecation and will be removed in " | ||||
|             "`detail_route` is deprecated and will be removed in " | ||||
|             "3.10 in favor of `action`, which accepts a `detail` bool. Use " | ||||
|             "`@action(detail=True)` instead." | ||||
|         ) | ||||
| 
 | ||||
|     def test_list_route_deprecation(self): | ||||
|         with pytest.warns(PendingDeprecationWarning) as record: | ||||
|         with pytest.warns(DeprecationWarning) as record: | ||||
|             @list_route() | ||||
|             def view(request): | ||||
|                 raise NotImplementedError | ||||
| 
 | ||||
|         assert len(record) == 1 | ||||
|         assert str(record[0].message) == ( | ||||
|             "`list_route` is pending deprecation and will be removed in " | ||||
|             "`list_route` is deprecated and will be removed in " | ||||
|             "3.10 in favor of `action`, which accepts a `detail` bool. Use " | ||||
|             "`@action(detail=False)` instead." | ||||
|         ) | ||||
| 
 | ||||
|     def test_route_url_name_from_path(self): | ||||
|         # pre-3.8 behavior was to base the `url_name` off of the `url_path` | ||||
|         with pytest.warns(PendingDeprecationWarning): | ||||
|         with pytest.warns(DeprecationWarning): | ||||
|             @list_route(url_path='foo_bar') | ||||
|             def view(request): | ||||
|                 raise NotImplementedError | ||||
|  |  | |||
|  | @ -495,18 +495,18 @@ class TestBaseNameRename(TestCase): | |||
|             warnings.simplefilter('always') | ||||
|             router.register('mock', MockViewSet, 'mock', base_name='mock') | ||||
| 
 | ||||
|         msg = "The `base_name` argument has been deprecated in favor of `basename`." | ||||
|         msg = "The `base_name` argument is pending deprecation in favor of `basename`." | ||||
|         assert len(w) == 1 | ||||
|         assert str(w[0].message) == msg | ||||
| 
 | ||||
|     def test_base_name_argument_deprecation(self): | ||||
|         router = SimpleRouter() | ||||
| 
 | ||||
|         with warnings.catch_warnings(record=True) as w: | ||||
|         with pytest.warns(PendingDeprecationWarning) as w: | ||||
|             warnings.simplefilter('always') | ||||
|             router.register('mock', MockViewSet, base_name='mock') | ||||
| 
 | ||||
|         msg = "The `base_name` argument has been deprecated in favor of `basename`." | ||||
|         msg = "The `base_name` argument is pending deprecation in favor of `basename`." | ||||
|         assert len(w) == 1 | ||||
|         assert str(w[0].message) == msg | ||||
|         assert router.registry == [ | ||||
|  | @ -529,7 +529,7 @@ class TestBaseNameRename(TestCase): | |||
|         msg = "`CustomRouter.get_default_base_name` method should be renamed `get_default_basename`." | ||||
| 
 | ||||
|         # Class definition should raise a warning | ||||
|         with warnings.catch_warnings(record=True) as w: | ||||
|         with pytest.warns(PendingDeprecationWarning) as w: | ||||
|             warnings.simplefilter('always') | ||||
| 
 | ||||
|             class CustomRouter(SimpleRouter): | ||||
|  |  | |||
|  | @ -1032,38 +1032,6 @@ class SchemaGenerationExclusionTests(TestCase): | |||
| 
 | ||||
|         assert should_include == expected | ||||
| 
 | ||||
|     def test_deprecations(self): | ||||
|         with pytest.warns(DeprecationWarning) as record: | ||||
|             @api_view(["GET"], exclude_from_schema=True) | ||||
|             def view(request): | ||||
|                 pass | ||||
| 
 | ||||
|         assert len(record) == 1 | ||||
|         assert str(record[0].message) == ( | ||||
|             "The `exclude_from_schema` argument to `api_view` is deprecated. " | ||||
|             "Use the `schema` decorator instead, passing `None`." | ||||
|         ) | ||||
| 
 | ||||
|         class OldFashionedExcludedView(APIView): | ||||
|             exclude_from_schema = True | ||||
| 
 | ||||
|             def get(self, request, *args, **kwargs): | ||||
|                 pass | ||||
| 
 | ||||
|         patterns = [ | ||||
|             url('^excluded-old-fashioned/$', OldFashionedExcludedView.as_view()), | ||||
|         ] | ||||
| 
 | ||||
|         inspector = EndpointEnumerator(patterns) | ||||
|         with pytest.warns(DeprecationWarning) as record: | ||||
|             inspector.get_api_endpoints() | ||||
| 
 | ||||
|         assert len(record) == 1 | ||||
|         assert str(record[0].message) == ( | ||||
|             "The `OldFashionedExcludedView.exclude_from_schema` attribute is " | ||||
|             "deprecated. Set `schema = None` instead." | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| @api_view(["GET"]) | ||||
| def simple_fbv(request): | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user