mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-05-01 06:23:42 +03:00
Version 3.8 Release (#5769)
This commit is contained in:
parent
1befab795a
commit
fc588f539b
|
@ -153,7 +153,7 @@ See the pagination documentation for further guidance on [setting the pagination
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**This setting is pending deprecation.**
|
**This setting has been removed.**
|
||||||
|
|
||||||
See the pagination documentation for further guidance on [setting the pagination style](pagination.md#modifying-the-pagination-style).
|
See the pagination documentation for further guidance on [setting the pagination style](pagination.md#modifying-the-pagination-style).
|
||||||
|
|
||||||
|
|
97
docs/topics/3.8-announcement.md
Normal file
97
docs/topics/3.8-announcement.md
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<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.8
|
||||||
|
|
||||||
|
The 3.8 release is a maintenance focused release resolving a large number of previously outstanding issues and laying
|
||||||
|
the foundations for future changes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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]**.
|
||||||
|
|
||||||
|
|
||||||
|
*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).*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
|
||||||
|
### Altered the behaviour of `read_only` plus `default` on Field.
|
||||||
|
|
||||||
|
[#5886][gh5886] `read_only` fields will now **always** be excluded from writable fields.
|
||||||
|
|
||||||
|
Previously `read_only` fields when combined with a `default` value would use the `default` for create and update
|
||||||
|
operations. This was counter-intuitive in some circumstances and led to difficulties supporting dotted `source`
|
||||||
|
attributes on nullable relations.
|
||||||
|
|
||||||
|
In order to maintain the old behaviour you may need to pass the value of `read_only` fields when calling `save()` in
|
||||||
|
the view:
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
serializer.save(owner=self.request.user)
|
||||||
|
|
||||||
|
Alternatively you may override `save()` or `create()` or `update()` on the serialiser as appropriate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deprecations
|
||||||
|
|
||||||
|
### `action` decorator replaces `list_route` and `detail_route`
|
||||||
|
|
||||||
|
[#5705][gh5705] `list_route` and `detail_route` have been merge into a single `action` decorator. This improves viewset action introspection, and will allow extra actions to be displayed in the Browsable API in future versions.
|
||||||
|
|
||||||
|
Both `list_route` and `detail_route` are now pending deprecation. They will be deprecated in 3.9 and removed entirely
|
||||||
|
in 3.10.
|
||||||
|
|
||||||
|
The new `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` decorator are now deprecated. They will be removed entirely in 3.9.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
We're currently working towards moving to using [OpenAPI][openapi] as our default schema output. We'll also be revisiting our API documentation generation and client libraries.
|
||||||
|
|
||||||
|
We're doing some consolidation in order to make this happen. It's planned that 3.9 will drop the `coreapi` and `coreschema` libraries, and instead use `apistar` for the API documentation generation, schema generation, and API client libraries.
|
||||||
|
|
||||||
|
[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,7 +42,41 @@ You can determine your currently installed version using `pip show`:
|
||||||
|
|
||||||
### 3.8.0
|
### 3.8.0
|
||||||
|
|
||||||
**Date**: [unreleased][3.8.0-milestone]
|
**Date**: [3rd April 2018][3.8.0-milestone]
|
||||||
|
|
||||||
|
|
||||||
|
* **Breaking Change**: Alter `read_only` plus `default` behaviour. [#5886][gh5886]
|
||||||
|
|
||||||
|
`read_only` fields will now **always** be excluded from writable fields.
|
||||||
|
|
||||||
|
Previously `read_only` fields with a `default` value would use the `default` for create and update operations.
|
||||||
|
|
||||||
|
In order to maintain the old behaviour you may need to pass the value of `read_only` fields when calling `save()` in
|
||||||
|
the view:
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
serializer.save(owner=self.request.user)
|
||||||
|
|
||||||
|
Alternatively you may override `save()` or `create()` or `update()` on the serialiser as appropriate.
|
||||||
|
* Correct allow_null behaviour when required=False [#5888][gh5888]
|
||||||
|
|
||||||
|
Without an explicit `default`, `allow_null` implies a default of `null` for outgoing serialisation. Previously such
|
||||||
|
fields were being skipped when read-only or otherwise not required.
|
||||||
|
|
||||||
|
**Possible backwards compatibility break** if you were relying on such fields being excluded from the outgoing
|
||||||
|
representation. In order to restore the old behaviour you can override `data` to exclude the field when `None`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
"""
|
||||||
|
Drop `maybe_none` field if None.
|
||||||
|
"""
|
||||||
|
data = super().data()
|
||||||
|
if 'maybe_none' in data and data['maybe_none'] is None:
|
||||||
|
del data['maybe_none']
|
||||||
|
return data
|
||||||
|
|
||||||
* Refactor dynamic route generation and improve viewset action introspectibility. [#5705][gh5705]
|
* Refactor dynamic route generation and improve viewset action introspectibility. [#5705][gh5705]
|
||||||
|
|
||||||
|
@ -62,6 +96,61 @@ You can determine your currently installed version using `pip show`:
|
||||||
* Deprecated `list_route` & `detail_route` in favor of `action` decorator with `detail` boolean.
|
* Deprecated `list_route` & `detail_route` in favor of `action` decorator with `detail` boolean.
|
||||||
* Deprecated dynamic list/detail route variants in favor of `DynamicRoute` with `detail` boolean.
|
* Deprecated dynamic list/detail route variants in favor of `DynamicRoute` with `detail` boolean.
|
||||||
* Refactored the router's dynamic route generation.
|
* Refactored the router's dynamic route generation.
|
||||||
|
* Fix formatting of the 3.7.4 release note [#5704][gh5704]
|
||||||
|
* Docs: Update DRF Writable Nested Serializers references [#5711][gh5711]
|
||||||
|
* Docs: Fixed typo in auth URLs example. [#5713][gh5713]
|
||||||
|
* Improve composite field child errors [#5655][gh5655]
|
||||||
|
* Disable HTML inputs for dict/list fields [#5702][gh5702]
|
||||||
|
* Fix typo in HostNameVersioning doc [#5709][gh5709]
|
||||||
|
* Use rsplit to get module and classname for imports [#5712][gh5712]
|
||||||
|
* Formalize URLPatternsTestCase [#5703][gh5703]
|
||||||
|
* Add exception translation test [#5700][gh5700]
|
||||||
|
* Test staticfiles [#5701][gh5701]
|
||||||
|
* Add drf-yasg to documentation and schema 3rd party packages [#5720][gh5720]
|
||||||
|
* Remove unused `compat._resolve_model()` [#5733][gh5733]
|
||||||
|
* Drop compat workaround for unsupported Python 3.2 [#5734][gh5734]
|
||||||
|
* Prefer `iter(dict)` over `iter(dict.keys())` [#5736][gh5736]
|
||||||
|
* Pass `python_requires` argument to setuptools [#5739][gh5739]
|
||||||
|
* Remove unused links from docs [#5735][gh5735]
|
||||||
|
* Prefer https protocol for links in docs when available [#5729][gh5729]
|
||||||
|
* Add HStoreField, postgres fields tests [#5654][gh5654]
|
||||||
|
* Always fully qualify ValidationError in docs [#5751][gh5751]
|
||||||
|
* Remove unreachable code from ManualSchema [#5766][gh5766]
|
||||||
|
* Allowed customising API documentation code samples [#5752][gh5752]
|
||||||
|
* Updated docs to use `pip show` [#5757][gh5757]
|
||||||
|
* Load 'static' instead of 'staticfiles' in templates [#5773][gh5773]
|
||||||
|
* Fixed a typo in `fields` docs [#5783][gh5783]
|
||||||
|
* Refer to "NamespaceVersioning" instead of "NamespacedVersioning" in the documentation [#5754][gh5754]
|
||||||
|
* ErrorDetail: add `__eq__`/`__ne__` and `__repr__` [#5787][gh5787]
|
||||||
|
* Replace `background-attachment: fixed` in docs [#5777][gh5777]
|
||||||
|
* Make 404 & 403 responses consistent with `exceptions.APIException` output [#5763][gh5763]
|
||||||
|
* Small fix to API documentation: schemas [#5796][gh5796]
|
||||||
|
* Fix schema generation for PrimaryKeyRelatedField [#5764][gh5764]
|
||||||
|
* Represent serializer DictField as an Object in schema [#5765][gh5765]
|
||||||
|
* Added docs example reimplementing ObtainAuthToken [#5802][gh5802]
|
||||||
|
* Add schema to the ObtainAuthToken view [#5676][gh5676]
|
||||||
|
* Fix request formdata handling [#5800][gh5800]
|
||||||
|
* Fix authtoken views imports [#5818][gh5818]
|
||||||
|
* Update pytest, isort [#5815][gh5815] [#5817][gh5817] [#5894][gh5894]
|
||||||
|
* Fixed active timezone handling for non ISO8601 datetimes. [#5833][gh5833]
|
||||||
|
* Made TemplateHTMLRenderer render IntegerField inputs when value is `0`. [#5834][gh5834]
|
||||||
|
* Corrected endpoint in tutorial instructions [#5835][gh5835]
|
||||||
|
* Add Django Rest Framework Role Filters to Third party packages [#5809][gh5809]
|
||||||
|
* Use single copy of static assets. Update jQuery [#5823][gh5823]
|
||||||
|
* Changes ternary conditionals to be PEP308 compliant [#5827][gh5827]
|
||||||
|
* Added links to 'A Todo List API with React' and 'Blog API' tutorials [#5837][gh5837]
|
||||||
|
* Fix comment typo in ModelSerializer [#5844][gh5844]
|
||||||
|
* Add admin to installed apps to avoid test failures. [#5870][gh5870]
|
||||||
|
* Fixed schema for UUIDField in SimpleMetadata. [#5872][gh5872]
|
||||||
|
* Corrected docs on router include with namespaces. [#5843][gh5843]
|
||||||
|
* Test using model objects for dotted source default [#5880][gh5880]
|
||||||
|
* Allow traversing nullable related fields [#5849][gh5849]
|
||||||
|
* Added: Tutorial: Django REST with React (Django 2.0) [#5891][gh5891]
|
||||||
|
* Add `LimitOffsetPagination.get_count` to allow method override [#5846][gh5846]
|
||||||
|
* Don't show hidden fields in metadata [#5854][gh5854]
|
||||||
|
* Enable OrderingFilter to handle an empty tuple (or list) for the 'ordering' field. [#5899][gh5899]
|
||||||
|
* Added generic 500 and 400 JSON error handlers. [#5904][gh5904]
|
||||||
|
|
||||||
|
|
||||||
## 3.7.x series
|
## 3.7.x series
|
||||||
|
|
||||||
|
@ -1778,4 +1867,62 @@ For older release notes, [please see the version 2.x documentation][old-release-
|
||||||
[gh5697]: https://github.com/encode/django-rest-framework/issues/5697
|
[gh5697]: https://github.com/encode/django-rest-framework/issues/5697
|
||||||
|
|
||||||
<!-- 3.8.0 -->
|
<!-- 3.8.0 -->
|
||||||
|
[gh5886]: https://github.com/encode/django-rest-framework/issues/5886
|
||||||
|
[gh5888]: https://github.com/encode/django-rest-framework/issues/5888
|
||||||
[gh5705]: https://github.com/encode/django-rest-framework/issues/5705
|
[gh5705]: https://github.com/encode/django-rest-framework/issues/5705
|
||||||
|
[gh5796]: https://github.com/encode/django-rest-framework/issues/5796
|
||||||
|
[gh5763]: https://github.com/encode/django-rest-framework/issues/5763
|
||||||
|
[gh5777]: https://github.com/encode/django-rest-framework/issues/5777
|
||||||
|
[gh5787]: https://github.com/encode/django-rest-framework/issues/5787
|
||||||
|
[gh5754]: https://github.com/encode/django-rest-framework/issues/5754
|
||||||
|
[gh5783]: https://github.com/encode/django-rest-framework/issues/5783
|
||||||
|
[gh5773]: https://github.com/encode/django-rest-framework/issues/5773
|
||||||
|
[gh5757]: https://github.com/encode/django-rest-framework/issues/5757
|
||||||
|
[gh5752]: https://github.com/encode/django-rest-framework/issues/5752
|
||||||
|
[gh5766]: https://github.com/encode/django-rest-framework/issues/5766
|
||||||
|
[gh5751]: https://github.com/encode/django-rest-framework/issues/5751
|
||||||
|
[gh5654]: https://github.com/encode/django-rest-framework/issues/5654
|
||||||
|
[gh5729]: https://github.com/encode/django-rest-framework/issues/5729
|
||||||
|
[gh5735]: https://github.com/encode/django-rest-framework/issues/5735
|
||||||
|
[gh5739]: https://github.com/encode/django-rest-framework/issues/5739
|
||||||
|
[gh5736]: https://github.com/encode/django-rest-framework/issues/5736
|
||||||
|
[gh5734]: https://github.com/encode/django-rest-framework/issues/5734
|
||||||
|
[gh5733]: https://github.com/encode/django-rest-framework/issues/5733
|
||||||
|
[gh5720]: https://github.com/encode/django-rest-framework/issues/5720
|
||||||
|
[gh5701]: https://github.com/encode/django-rest-framework/issues/5701
|
||||||
|
[gh5700]: https://github.com/encode/django-rest-framework/issues/5700
|
||||||
|
[gh5703]: https://github.com/encode/django-rest-framework/issues/5703
|
||||||
|
[gh5712]: https://github.com/encode/django-rest-framework/issues/5712
|
||||||
|
[gh5709]: https://github.com/encode/django-rest-framework/issues/5709
|
||||||
|
[gh5702]: https://github.com/encode/django-rest-framework/issues/5702
|
||||||
|
[gh5655]: https://github.com/encode/django-rest-framework/issues/5655
|
||||||
|
[gh5713]: https://github.com/encode/django-rest-framework/issues/5713
|
||||||
|
[gh5711]: https://github.com/encode/django-rest-framework/issues/5711
|
||||||
|
[gh5704]: https://github.com/encode/django-rest-framework/issues/5704
|
||||||
|
[gh5854]: https://github.com/encode/django-rest-framework/issues/5854
|
||||||
|
[gh5846]: https://github.com/encode/django-rest-framework/issues/5846
|
||||||
|
[gh5891]: https://github.com/encode/django-rest-framework/issues/5891
|
||||||
|
[gh5849]: https://github.com/encode/django-rest-framework/issues/5849
|
||||||
|
[gh5880]: https://github.com/encode/django-rest-framework/issues/5880
|
||||||
|
[gh5843]: https://github.com/encode/django-rest-framework/issues/5843
|
||||||
|
[gh5872]: https://github.com/encode/django-rest-framework/issues/5872
|
||||||
|
[gh5870]: https://github.com/encode/django-rest-framework/issues/5870
|
||||||
|
[gh5844]: https://github.com/encode/django-rest-framework/issues/5844
|
||||||
|
[gh5837]: https://github.com/encode/django-rest-framework/issues/5837
|
||||||
|
[gh5827]: https://github.com/encode/django-rest-framework/issues/5827
|
||||||
|
[gh5823]: https://github.com/encode/django-rest-framework/issues/5823
|
||||||
|
[gh5809]: https://github.com/encode/django-rest-framework/issues/5809
|
||||||
|
[gh5835]: https://github.com/encode/django-rest-framework/issues/5835
|
||||||
|
[gh5834]: https://github.com/encode/django-rest-framework/issues/5834
|
||||||
|
[gh5833]: https://github.com/encode/django-rest-framework/issues/5833
|
||||||
|
[gh5894]: https://github.com/encode/django-rest-framework/issues/5894
|
||||||
|
[gh5817]: https://github.com/encode/django-rest-framework/issues/5817
|
||||||
|
[gh5815]: https://github.com/encode/django-rest-framework/issues/5815
|
||||||
|
[gh5818]: https://github.com/encode/django-rest-framework/issues/5818
|
||||||
|
[gh5800]: https://github.com/encode/django-rest-framework/issues/5800
|
||||||
|
[gh5676]: https://github.com/encode/django-rest-framework/issues/5676
|
||||||
|
[gh5802]: https://github.com/encode/django-rest-framework/issues/5802
|
||||||
|
[gh5765]: https://github.com/encode/django-rest-framework/issues/5765
|
||||||
|
[gh5764]: https://github.com/encode/django-rest-framework/issues/5764
|
||||||
|
[gh5904]: https://github.com/encode/django-rest-framework/issues/5904
|
||||||
|
[gh5899]: https://github.com/encode/django-rest-framework/issues/5899
|
||||||
|
|
|
@ -8,10 +8,10 @@ ______ _____ _____ _____ __
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__title__ = 'Django REST framework'
|
__title__ = 'Django REST framework'
|
||||||
__version__ = '3.7.7'
|
__version__ = '3.8.0'
|
||||||
__author__ = 'Tom Christie'
|
__author__ = 'Tom Christie'
|
||||||
__license__ = 'BSD 2-Clause'
|
__license__ = 'BSD 2-Clause'
|
||||||
__copyright__ = 'Copyright 2011-2017 Tom Christie'
|
__copyright__ = 'Copyright 2011-2018 Tom Christie'
|
||||||
|
|
||||||
# Version synonym
|
# Version synonym
|
||||||
VERSION = __version__
|
VERSION = __version__
|
||||||
|
|
|
@ -78,9 +78,9 @@ def api_view(http_method_names=None, exclude_from_schema=False):
|
||||||
|
|
||||||
if exclude_from_schema:
|
if exclude_from_schema:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The `exclude_from_schema` argument to `api_view` is pending deprecation. "
|
"The `exclude_from_schema` argument to `api_view` is deprecated. "
|
||||||
"Use the `schema` decorator instead, passing `None`.",
|
"Use the `schema` decorator instead, passing `None`.",
|
||||||
PendingDeprecationWarning
|
DeprecationWarning
|
||||||
)
|
)
|
||||||
WrappedAPIView.exclude_from_schema = exclude_from_schema
|
WrappedAPIView.exclude_from_schema = exclude_from_schema
|
||||||
|
|
||||||
|
|
|
@ -208,10 +208,10 @@ class EndpointEnumerator(object):
|
||||||
return False # Ignore anything except REST framework views.
|
return False # Ignore anything except REST framework views.
|
||||||
|
|
||||||
if hasattr(callback.cls, 'exclude_from_schema'):
|
if hasattr(callback.cls, 'exclude_from_schema'):
|
||||||
fmt = ("The `{}.exclude_from_schema` attribute is pending deprecation. "
|
fmt = ("The `{}.exclude_from_schema` attribute is deprecated. "
|
||||||
"Set `schema = None` instead.")
|
"Set `schema = None` instead.")
|
||||||
msg = fmt.format(callback.cls.__name__)
|
msg = fmt.format(callback.cls.__name__)
|
||||||
warnings.warn(msg, PendingDeprecationWarning)
|
warnings.warn(msg, DeprecationWarning)
|
||||||
if getattr(callback.cls, 'exclude_from_schema', False):
|
if getattr(callback.cls, 'exclude_from_schema', False):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -871,15 +871,15 @@ class SchemaGenerationExclusionTests(TestCase):
|
||||||
assert should_include == expected
|
assert should_include == expected
|
||||||
|
|
||||||
def test_deprecations(self):
|
def test_deprecations(self):
|
||||||
with pytest.warns(PendingDeprecationWarning) as record:
|
with pytest.warns(DeprecationWarning) as record:
|
||||||
@api_view(["GET"], exclude_from_schema=True)
|
@api_view(["GET"], exclude_from_schema=True)
|
||||||
def view(request):
|
def view(request):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert len(record) == 1
|
assert len(record) == 1
|
||||||
assert str(record[0].message) == (
|
assert str(record[0].message) == (
|
||||||
"The `exclude_from_schema` argument to `api_view` is pending "
|
"The `exclude_from_schema` argument to `api_view` is deprecated. "
|
||||||
"deprecation. Use the `schema` decorator instead, passing `None`."
|
"Use the `schema` decorator instead, passing `None`."
|
||||||
)
|
)
|
||||||
|
|
||||||
class OldFashionedExcludedView(APIView):
|
class OldFashionedExcludedView(APIView):
|
||||||
|
@ -893,13 +893,13 @@ class SchemaGenerationExclusionTests(TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
inspector = EndpointEnumerator(patterns)
|
inspector = EndpointEnumerator(patterns)
|
||||||
with pytest.warns(PendingDeprecationWarning) as record:
|
with pytest.warns(DeprecationWarning) as record:
|
||||||
inspector.get_api_endpoints()
|
inspector.get_api_endpoints()
|
||||||
|
|
||||||
assert len(record) == 1
|
assert len(record) == 1
|
||||||
assert str(record[0].message) == (
|
assert str(record[0].message) == (
|
||||||
"The `OldFashionedExcludedView.exclude_from_schema` attribute is "
|
"The `OldFashionedExcludedView.exclude_from_schema` attribute is "
|
||||||
"pending deprecation. Set `schema = None` instead."
|
"deprecated. Set `schema = None` instead."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user