Version 3.14.0 proposal (#8599)

* Version 3.14.0

* Update docs/community/release-notes.md to use proper links.

Co-authored-by: Adam Johnson <me@adamj.eu>

* Add community announcement page for version 3.14

* Remove deprecated NullBooleanField.

* Change openapi _get_reference removal to 3.15

This deprecation was never released in the 3.13.x series and therefore
can't be removed at the same time the replacement is released.

* Removing deprecated openapi methods.

Co-authored-by: Adam Johnson <me@adamj.eu>
This commit is contained in:
Tim Schilling 2022-09-21 08:08:12 -05:00 committed by GitHub
parent 51f1aff162
commit b658915846
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 141 deletions

View File

@ -159,14 +159,6 @@ Corresponds to `django.db.models.fields.BooleanField`.
**Signature:** `BooleanField()` **Signature:** `BooleanField()`
## NullBooleanField
A boolean representation that also accepts `None` as a valid value.
Corresponds to `django.db.models.fields.NullBooleanField`.
**Signature:** `NullBooleanField()`
--- ---
# String fields # String fields

View File

@ -0,0 +1,62 @@
<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.14
## Django 4.1 support
The latest release now fully supports Django 4.1.
Our requirements are now:
* Python 3.6+
* Django 4.1, 4.0, 3.2, 3.1, 2.2 (LTS)
## `raise_exceptions` argument for `is_valid` is now keyword-only.
Calling `serializer_instance.is_valid(True)` is no longer acceptable syntax.
If you'd like to use the `raise_exceptions` argument, you must use it as a
keyword argument.
See Pull Request [#7952](https://github.com/encode/django-rest-framework/pull/7952) for more details.
## `ManyRelatedField` supports returning the default when the source attribute doesn't exist.
Previously, if you used a serializer field with `many=True` with a dot notated source field
that didn't exist, it would raise an `AttributeError`. Now it will return the default or be
skipped depending on the other arguments.
See Pull Request [#7574](https://github.com/encode/django-rest-framework/pull/7574) for more details.
## Make Open API `get_reference` public.
Returns a reference to the serializer component. This may be useful if you override `get_schema()`.
## Change semantic of OR of two permission classes.
When OR-ing two permissions, the request has to pass either class's `has_permission() and has_object_permission()`.
Previously, both class's `has_permission()` was ignored when OR-ing two permissions together.
See Pull Request [#7522](https://github.com/encode/django-rest-framework/pull/7522) for more details.
## Minor fixes and improvements
There are a number of minor fixes and improvements in this release. See the [release notes](release-notes.md) page for a complete listing.

View File

@ -34,6 +34,23 @@ You can determine your currently installed version using `pip show`:
--- ---
## 3.14.x series
### 3.14.0
Date: 10th August 2022
* Enforce `is_valid(raise_exception=False)` as a keyword-only argument. [[#7952](https://github.com/encode/django-rest-framework/pull/7952)]
* Django 4.1 compatability. [[#8591](https://github.com/encode/django-rest-framework/pull/8591)]
* Stop calling `set_context` on Validators. [[#8589](https://github.com/encode/django-rest-framework/pull/8589)]
* Return `NotImplemented` from `ErrorDetails.__ne__`. [[#8538](https://github.com/encode/django-rest-framework/pull/8538)]
* Don't evaluate `DateTimeField.default_timezone` when a custom timezone is set. [[#8531](https://github.com/encode/django-rest-framework/pull/8531)]
* Make relative URLs clickable in Browseable API. [[#8464](https://github.com/encode/django-rest-framework/pull/8464)]
* Support `ManyRelatedField` falling back to the default value when the attribute specified by dot notation doesn't exist. Matches `ManyRelatedField.get_attribute` to `Field.get_attribute`. [[#7574](https://github.com/encode/django-rest-framework/pull/7574)]
* Make `schemas.openapi.get_reference` public. [[#7515](https://github.com/encode/django-rest-framework/pull/7515)]
* Make `ReturnDict` support `dict` union operators on Python 3.9 and later. [[#8302](https://github.com/encode/django-rest-framework/pull/8302)]
* Update throttling to check if `request.user` is set before checking if the user is authenticated. [[#8370](https://github.com/encode/django-rest-framework/pull/8370)]
## 3.13.x series ## 3.13.x series
### 3.13.1 ### 3.13.1

View File

@ -10,7 +10,7 @@ ______ _____ _____ _____ __
import django import django
__title__ = 'Django REST framework' __title__ = 'Django REST framework'
__version__ = '3.13.1' __version__ = '3.14.0'
__author__ = 'Tom Christie' __author__ = 'Tom Christie'
__license__ = 'BSD 3-Clause' __license__ = 'BSD 3-Clause'
__copyright__ = 'Copyright 2011-2019 Encode OSS Ltd' __copyright__ = 'Copyright 2011-2019 Encode OSS Ltd'
@ -35,3 +35,7 @@ class RemovedInDRF313Warning(DeprecationWarning):
class RemovedInDRF314Warning(PendingDeprecationWarning): class RemovedInDRF314Warning(PendingDeprecationWarning):
pass pass
class RemovedInDRF315Warning(PendingDeprecationWarning):
pass

View File

@ -5,7 +5,6 @@ import functools
import inspect import inspect
import re import re
import uuid import uuid
import warnings
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Mapping from collections.abc import Mapping
@ -30,7 +29,7 @@ from django.utils.ipv6 import clean_ipv6_address
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from pytz.exceptions import InvalidTimeError from pytz.exceptions import InvalidTimeError
from rest_framework import ISO_8601, RemovedInDRF314Warning from rest_framework import ISO_8601
from rest_framework.exceptions import ErrorDetail, ValidationError from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
from rest_framework.utils import html, humanize_datetime, json, representation from rest_framework.utils import html, humanize_datetime, json, representation
@ -712,23 +711,6 @@ class BooleanField(Field):
return bool(value) return bool(value)
class NullBooleanField(BooleanField):
initial = None
def __init__(self, **kwargs):
warnings.warn(
"The `NullBooleanField` is deprecated and will be removed starting "
"with 3.14. Instead use the `BooleanField` field and set "
"`allow_null=True` which does the same thing.",
RemovedInDRF314Warning, stacklevel=2
)
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.'
kwargs['allow_null'] = True
super().__init__(**kwargs)
# String types... # String types...
class CharField(Field): class CharField(Field):

View File

@ -36,7 +36,6 @@ class SimpleMetadata(BaseMetadata):
label_lookup = ClassLookupDict({ label_lookup = ClassLookupDict({
serializers.Field: 'field', serializers.Field: 'field',
serializers.BooleanField: 'boolean', serializers.BooleanField: 'boolean',
serializers.NullBooleanField: 'boolean',
serializers.CharField: 'string', serializers.CharField: 'string',
serializers.UUIDField: 'string', serializers.UUIDField: 'string',
serializers.URLField: 'url', serializers.URLField: 'url',

View File

@ -13,7 +13,7 @@ from django.db import models
from django.utils.encoding import force_str from django.utils.encoding import force_str
from rest_framework import ( from rest_framework import (
RemovedInDRF314Warning, exceptions, renderers, serializers RemovedInDRF315Warning, exceptions, renderers, serializers
) )
from rest_framework.compat import uritemplate from rest_framework.compat import uritemplate
from rest_framework.fields import _UnvalidatedField, empty from rest_framework.fields import _UnvalidatedField, empty
@ -713,106 +713,10 @@ class AutoSchema(ViewInspector):
return [path.split('/')[0].replace('_', '-')] return [path.split('/')[0].replace('_', '-')]
def _get_path_parameters(self, path, method):
warnings.warn(
"Method `_get_path_parameters()` has been renamed to `get_path_parameters()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.get_path_parameters(path, method)
def _get_filter_parameters(self, path, method):
warnings.warn(
"Method `_get_filter_parameters()` has been renamed to `get_filter_parameters()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.get_filter_parameters(path, method)
def _get_responses(self, path, method):
warnings.warn(
"Method `_get_responses()` has been renamed to `get_responses()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.get_responses(path, method)
def _get_request_body(self, path, method):
warnings.warn(
"Method `_get_request_body()` has been renamed to `get_request_body()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.get_request_body(path, method)
def _get_serializer(self, path, method):
warnings.warn(
"Method `_get_serializer()` has been renamed to `get_serializer()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.get_serializer(path, method)
def _get_paginator(self):
warnings.warn(
"Method `_get_paginator()` has been renamed to `get_paginator()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.get_paginator()
def _map_field_validators(self, field, schema):
warnings.warn(
"Method `_map_field_validators()` has been renamed to `map_field_validators()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.map_field_validators(field, schema)
def _map_serializer(self, serializer):
warnings.warn(
"Method `_map_serializer()` has been renamed to `map_serializer()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.map_serializer(serializer)
def _map_field(self, field):
warnings.warn(
"Method `_map_field()` has been renamed to `map_field()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.map_field(field)
def _map_choicefield(self, field):
warnings.warn(
"Method `_map_choicefield()` has been renamed to `map_choicefield()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.map_choicefield(field)
def _get_pagination_parameters(self, path, method):
warnings.warn(
"Method `_get_pagination_parameters()` has been renamed to `get_pagination_parameters()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.get_pagination_parameters(path, method)
def _allows_filters(self, path, method):
warnings.warn(
"Method `_allows_filters()` has been renamed to `allows_filters()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
)
return self.allows_filters(path, method)
def _get_reference(self, serializer): def _get_reference(self, serializer):
warnings.warn( warnings.warn(
"Method `_get_reference()` has been renamed to `get_reference()`. " "Method `_get_reference()` has been renamed to `get_reference()`. "
"The old name will be removed in DRF v3.14.", "The old name will be removed in DRF v3.15.",
RemovedInDRF314Warning, stacklevel=2 RemovedInDRF315Warning, stacklevel=2
) )
return self.get_reference(serializer) return self.get_reference(serializer)

View File

@ -52,7 +52,7 @@ from rest_framework.fields import ( # NOQA # isort:skip
BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField, BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField,
DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField, DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField,
HiddenField, HStoreField, IPAddressField, ImageField, IntegerField, JSONField, HiddenField, HStoreField, IPAddressField, ImageField, IntegerField, JSONField,
ListField, ModelField, MultipleChoiceField, NullBooleanField, ReadOnlyField, ListField, ModelField, MultipleChoiceField, ReadOnlyField,
RegexField, SerializerMethodField, SlugField, TimeField, URLField, UUIDField, RegexField, SerializerMethodField, SlugField, TimeField, URLField, UUIDField,
) )
from rest_framework.relations import ( # NOQA # isort:skip from rest_framework.relations import ( # NOQA # isort:skip

View File

@ -679,9 +679,9 @@ class TestBooleanField(FieldValues):
assert exc_info.value.detail == expected assert exc_info.value.detail == expected
class TestNullBooleanField(TestBooleanField): class TestNullableBooleanField(TestBooleanField):
""" """
Valid and invalid values for `NullBooleanField`. Valid and invalid values for `BooleanField` when `allow_null=True`.
""" """
valid_inputs = { valid_inputs = {
'true': True, 'true': True,
@ -706,16 +706,6 @@ class TestNullBooleanField(TestBooleanField):
field = serializers.BooleanField(allow_null=True) field = serializers.BooleanField(allow_null=True)
class TestNullableBooleanField(TestNullBooleanField):
"""
Valid and invalid values for `BooleanField` when `allow_null=True`.
"""
@property
def field(self):
return serializers.BooleanField(allow_null=True)
# String types... # String types...
class TestCharField(FieldValues): class TestCharField(FieldValues):