Skip to content

Commit b658915

Browse files
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>
1 parent 51f1aff commit b658915

File tree

9 files changed

+91
-141
lines changed

9 files changed

+91
-141
lines changed

docs/api-guide/fields.md

-8
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,6 @@ Corresponds to `django.db.models.fields.BooleanField`.
159159

160160
**Signature:** `BooleanField()`
161161

162-
## NullBooleanField
163-
164-
A boolean representation that also accepts `None` as a valid value.
165-
166-
Corresponds to `django.db.models.fields.NullBooleanField`.
167-
168-
**Signature:** `NullBooleanField()`
169-
170162
---
171163

172164
# String fields

docs/community/3.14-announcement.md

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<style>
2+
.promo li a {
3+
float: left;
4+
width: 130px;
5+
height: 20px;
6+
text-align: center;
7+
margin: 10px 30px;
8+
padding: 150px 0 0 0;
9+
background-position: 0 50%;
10+
background-size: 130px auto;
11+
background-repeat: no-repeat;
12+
font-size: 120%;
13+
color: black;
14+
}
15+
.promo li {
16+
list-style: none;
17+
}
18+
</style>
19+
20+
# Django REST framework 3.14
21+
22+
## Django 4.1 support
23+
24+
The latest release now fully supports Django 4.1.
25+
26+
Our requirements are now:
27+
28+
* Python 3.6+
29+
* Django 4.1, 4.0, 3.2, 3.1, 2.2 (LTS)
30+
31+
## `raise_exceptions` argument for `is_valid` is now keyword-only.
32+
33+
Calling `serializer_instance.is_valid(True)` is no longer acceptable syntax.
34+
If you'd like to use the `raise_exceptions` argument, you must use it as a
35+
keyword argument.
36+
37+
See Pull Request [#7952](https://github.com/encode/django-rest-framework/pull/7952) for more details.
38+
39+
## `ManyRelatedField` supports returning the default when the source attribute doesn't exist.
40+
41+
Previously, if you used a serializer field with `many=True` with a dot notated source field
42+
that didn't exist, it would raise an `AttributeError`. Now it will return the default or be
43+
skipped depending on the other arguments.
44+
45+
See Pull Request [#7574](https://github.com/encode/django-rest-framework/pull/7574) for more details.
46+
47+
48+
## Make Open API `get_reference` public.
49+
50+
Returns a reference to the serializer component. This may be useful if you override `get_schema()`.
51+
52+
## Change semantic of OR of two permission classes.
53+
54+
When OR-ing two permissions, the request has to pass either class's `has_permission() and has_object_permission()`.
55+
56+
Previously, both class's `has_permission()` was ignored when OR-ing two permissions together.
57+
58+
See Pull Request [#7522](https://github.com/encode/django-rest-framework/pull/7522) for more details.
59+
60+
## Minor fixes and improvements
61+
62+
There are a number of minor fixes and improvements in this release. See the [release notes](release-notes.md) page for a complete listing.

docs/community/release-notes.md

+17
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@ You can determine your currently installed version using `pip show`:
3434

3535
---
3636

37+
## 3.14.x series
38+
39+
### 3.14.0
40+
41+
Date: 10th August 2022
42+
43+
* Enforce `is_valid(raise_exception=False)` as a keyword-only argument. [[#7952](https://github.com/encode/django-rest-framework/pull/7952)]
44+
* Django 4.1 compatability. [[#8591](https://github.com/encode/django-rest-framework/pull/8591)]
45+
* Stop calling `set_context` on Validators. [[#8589](https://github.com/encode/django-rest-framework/pull/8589)]
46+
* Return `NotImplemented` from `ErrorDetails.__ne__`. [[#8538](https://github.com/encode/django-rest-framework/pull/8538)]
47+
* Don't evaluate `DateTimeField.default_timezone` when a custom timezone is set. [[#8531](https://github.com/encode/django-rest-framework/pull/8531)]
48+
* Make relative URLs clickable in Browseable API. [[#8464](https://github.com/encode/django-rest-framework/pull/8464)]
49+
* 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)]
50+
* Make `schemas.openapi.get_reference` public. [[#7515](https://github.com/encode/django-rest-framework/pull/7515)]
51+
* Make `ReturnDict` support `dict` union operators on Python 3.9 and later. [[#8302](https://github.com/encode/django-rest-framework/pull/8302)]
52+
* 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)]
53+
3754
## 3.13.x series
3855

3956
### 3.13.1

rest_framework/__init__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import django
1111

1212
__title__ = 'Django REST framework'
13-
__version__ = '3.13.1'
13+
__version__ = '3.14.0'
1414
__author__ = 'Tom Christie'
1515
__license__ = 'BSD 3-Clause'
1616
__copyright__ = 'Copyright 2011-2019 Encode OSS Ltd'
@@ -35,3 +35,7 @@ class RemovedInDRF313Warning(DeprecationWarning):
3535

3636
class RemovedInDRF314Warning(PendingDeprecationWarning):
3737
pass
38+
39+
40+
class RemovedInDRF315Warning(PendingDeprecationWarning):
41+
pass

rest_framework/fields.py

+1-19
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import inspect
66
import re
77
import uuid
8-
import warnings
98
from collections import OrderedDict
109
from collections.abc import Mapping
1110

@@ -30,7 +29,7 @@
3029
from django.utils.translation import gettext_lazy as _
3130
from pytz.exceptions import InvalidTimeError
3231

33-
from rest_framework import ISO_8601, RemovedInDRF314Warning
32+
from rest_framework import ISO_8601
3433
from rest_framework.exceptions import ErrorDetail, ValidationError
3534
from rest_framework.settings import api_settings
3635
from rest_framework.utils import html, humanize_datetime, json, representation
@@ -712,23 +711,6 @@ def to_representation(self, value):
712711
return bool(value)
713712

714713

715-
class NullBooleanField(BooleanField):
716-
initial = None
717-
718-
def __init__(self, **kwargs):
719-
warnings.warn(
720-
"The `NullBooleanField` is deprecated and will be removed starting "
721-
"with 3.14. Instead use the `BooleanField` field and set "
722-
"`allow_null=True` which does the same thing.",
723-
RemovedInDRF314Warning, stacklevel=2
724-
)
725-
726-
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.'
727-
kwargs['allow_null'] = True
728-
729-
super().__init__(**kwargs)
730-
731-
732714
# String types...
733715

734716
class CharField(Field):

rest_framework/metadata.py

-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class SimpleMetadata(BaseMetadata):
3636
label_lookup = ClassLookupDict({
3737
serializers.Field: 'field',
3838
serializers.BooleanField: 'boolean',
39-
serializers.NullBooleanField: 'boolean',
4039
serializers.CharField: 'string',
4140
serializers.UUIDField: 'string',
4241
serializers.URLField: 'url',

rest_framework/schemas/openapi.py

+3-99
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from django.utils.encoding import force_str
1414

1515
from rest_framework import (
16-
RemovedInDRF314Warning, exceptions, renderers, serializers
16+
RemovedInDRF315Warning, exceptions, renderers, serializers
1717
)
1818
from rest_framework.compat import uritemplate
1919
from rest_framework.fields import _UnvalidatedField, empty
@@ -713,106 +713,10 @@ def get_tags(self, path, method):
713713

714714
return [path.split('/')[0].replace('_', '-')]
715715

716-
def _get_path_parameters(self, path, method):
717-
warnings.warn(
718-
"Method `_get_path_parameters()` has been renamed to `get_path_parameters()`. "
719-
"The old name will be removed in DRF v3.14.",
720-
RemovedInDRF314Warning, stacklevel=2
721-
)
722-
return self.get_path_parameters(path, method)
723-
724-
def _get_filter_parameters(self, path, method):
725-
warnings.warn(
726-
"Method `_get_filter_parameters()` has been renamed to `get_filter_parameters()`. "
727-
"The old name will be removed in DRF v3.14.",
728-
RemovedInDRF314Warning, stacklevel=2
729-
)
730-
return self.get_filter_parameters(path, method)
731-
732-
def _get_responses(self, path, method):
733-
warnings.warn(
734-
"Method `_get_responses()` has been renamed to `get_responses()`. "
735-
"The old name will be removed in DRF v3.14.",
736-
RemovedInDRF314Warning, stacklevel=2
737-
)
738-
return self.get_responses(path, method)
739-
740-
def _get_request_body(self, path, method):
741-
warnings.warn(
742-
"Method `_get_request_body()` has been renamed to `get_request_body()`. "
743-
"The old name will be removed in DRF v3.14.",
744-
RemovedInDRF314Warning, stacklevel=2
745-
)
746-
return self.get_request_body(path, method)
747-
748-
def _get_serializer(self, path, method):
749-
warnings.warn(
750-
"Method `_get_serializer()` has been renamed to `get_serializer()`. "
751-
"The old name will be removed in DRF v3.14.",
752-
RemovedInDRF314Warning, stacklevel=2
753-
)
754-
return self.get_serializer(path, method)
755-
756-
def _get_paginator(self):
757-
warnings.warn(
758-
"Method `_get_paginator()` has been renamed to `get_paginator()`. "
759-
"The old name will be removed in DRF v3.14.",
760-
RemovedInDRF314Warning, stacklevel=2
761-
)
762-
return self.get_paginator()
763-
764-
def _map_field_validators(self, field, schema):
765-
warnings.warn(
766-
"Method `_map_field_validators()` has been renamed to `map_field_validators()`. "
767-
"The old name will be removed in DRF v3.14.",
768-
RemovedInDRF314Warning, stacklevel=2
769-
)
770-
return self.map_field_validators(field, schema)
771-
772-
def _map_serializer(self, serializer):
773-
warnings.warn(
774-
"Method `_map_serializer()` has been renamed to `map_serializer()`. "
775-
"The old name will be removed in DRF v3.14.",
776-
RemovedInDRF314Warning, stacklevel=2
777-
)
778-
return self.map_serializer(serializer)
779-
780-
def _map_field(self, field):
781-
warnings.warn(
782-
"Method `_map_field()` has been renamed to `map_field()`. "
783-
"The old name will be removed in DRF v3.14.",
784-
RemovedInDRF314Warning, stacklevel=2
785-
)
786-
return self.map_field(field)
787-
788-
def _map_choicefield(self, field):
789-
warnings.warn(
790-
"Method `_map_choicefield()` has been renamed to `map_choicefield()`. "
791-
"The old name will be removed in DRF v3.14.",
792-
RemovedInDRF314Warning, stacklevel=2
793-
)
794-
return self.map_choicefield(field)
795-
796-
def _get_pagination_parameters(self, path, method):
797-
warnings.warn(
798-
"Method `_get_pagination_parameters()` has been renamed to `get_pagination_parameters()`. "
799-
"The old name will be removed in DRF v3.14.",
800-
RemovedInDRF314Warning, stacklevel=2
801-
)
802-
return self.get_pagination_parameters(path, method)
803-
804-
def _allows_filters(self, path, method):
805-
warnings.warn(
806-
"Method `_allows_filters()` has been renamed to `allows_filters()`. "
807-
"The old name will be removed in DRF v3.14.",
808-
RemovedInDRF314Warning, stacklevel=2
809-
)
810-
return self.allows_filters(path, method)
811-
812716
def _get_reference(self, serializer):
813717
warnings.warn(
814718
"Method `_get_reference()` has been renamed to `get_reference()`. "
815-
"The old name will be removed in DRF v3.14.",
816-
RemovedInDRF314Warning, stacklevel=2
719+
"The old name will be removed in DRF v3.15.",
720+
RemovedInDRF315Warning, stacklevel=2
817721
)
818722
return self.get_reference(serializer)

rest_framework/serializers.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField,
5353
DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField,
5454
HiddenField, HStoreField, IPAddressField, ImageField, IntegerField, JSONField,
55-
ListField, ModelField, MultipleChoiceField, NullBooleanField, ReadOnlyField,
55+
ListField, ModelField, MultipleChoiceField, ReadOnlyField,
5656
RegexField, SerializerMethodField, SlugField, TimeField, URLField, UUIDField,
5757
)
5858
from rest_framework.relations import ( # NOQA # isort:skip

tests/test_fields.py

+2-12
Original file line numberDiff line numberDiff line change
@@ -679,9 +679,9 @@ def test_disallow_unhashable_collection_types(self):
679679
assert exc_info.value.detail == expected
680680

681681

682-
class TestNullBooleanField(TestBooleanField):
682+
class TestNullableBooleanField(TestBooleanField):
683683
"""
684-
Valid and invalid values for `NullBooleanField`.
684+
Valid and invalid values for `BooleanField` when `allow_null=True`.
685685
"""
686686
valid_inputs = {
687687
'true': True,
@@ -706,16 +706,6 @@ class TestNullBooleanField(TestBooleanField):
706706
field = serializers.BooleanField(allow_null=True)
707707

708708

709-
class TestNullableBooleanField(TestNullBooleanField):
710-
"""
711-
Valid and invalid values for `BooleanField` when `allow_null=True`.
712-
"""
713-
714-
@property
715-
def field(self):
716-
return serializers.BooleanField(allow_null=True)
717-
718-
719709
# String types...
720710

721711
class TestCharField(FieldValues):

0 commit comments

Comments
 (0)