Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 3.14.0 proposal #8599

Merged
merged 6 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions docs/api-guide/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,6 @@ Corresponds to `django.db.models.fields.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
Expand Down
62 changes: 62 additions & 0 deletions docs/community/3.14-announcement.md
Original file line number Diff line number Diff line change
@@ -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+
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho this should be 3.7+ but we need #8518 to be merged

Suggested change
* Python 3.6+
* Python 3.7+

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be happy merging that but I'll defer to @tomchristie.

* Django 4.1, 4.0, 3.2, 3.1, 2.2 (LTS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Django 4.1, 4.0, 3.2, 3.1, 2.2 (LTS)
* Django 4.1, 4.0, 3.2 (LTS)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do the related clean ups in a separate PR as well.


## `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.
17 changes: 17 additions & 0 deletions docs/community/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.1
Expand Down
6 changes: 5 additions & 1 deletion rest_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import django

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

class RemovedInDRF314Warning(PendingDeprecationWarning):
pass
Comment on lines 36 to 37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this and the above RemovedInDRF313Warning can be removed? I cannot find any other references.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept it as per the comments in #8589.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That argument doesn't really convince me, DRF has never kept around the old warning classes for previous versions, e.g. RemovedInDRF312Warning was removed in d45e000. Similarly, Django does not keep around old warning classes "just in case".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather leave that decision up to a maintainer. I wasn't a part of the original discussion so it'd be disingenuous for me to say that by convincing me, the past argument is moot.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to have missed this thread!

I was assuming that RemovedInDRF313Warning would be deleted with the 3.14 release.
(My point was only that deleting an exception class in a minor release would constitute a breaking change)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CC @adamchainz - put out a PR to delete the now-unused warnings: #8664



class RemovedInDRF315Warning(PendingDeprecationWarning):
pass
20 changes: 1 addition & 19 deletions rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import inspect
import re
import uuid
import warnings
from collections import OrderedDict
from collections.abc import Mapping

Expand All @@ -30,7 +29,7 @@
from django.utils.translation import gettext_lazy as _
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.settings import api_settings
from rest_framework.utils import html, humanize_datetime, json, representation
Expand Down Expand Up @@ -712,23 +711,6 @@ def to_representation(self, 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...

class CharField(Field):
Expand Down
1 change: 0 additions & 1 deletion rest_framework/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class SimpleMetadata(BaseMetadata):
label_lookup = ClassLookupDict({
serializers.Field: 'field',
serializers.BooleanField: 'boolean',
serializers.NullBooleanField: 'boolean',
serializers.CharField: 'string',
serializers.UUIDField: 'string',
serializers.URLField: 'url',
Expand Down
102 changes: 3 additions & 99 deletions rest_framework/schemas/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from django.utils.encoding import force_str

from rest_framework import (
RemovedInDRF314Warning, exceptions, renderers, serializers
RemovedInDRF315Warning, exceptions, renderers, serializers
)
from rest_framework.compat import uritemplate
from rest_framework.fields import _UnvalidatedField, empty
Expand Down Expand Up @@ -713,106 +713,10 @@ def get_tags(self, path, method):

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):
warnings.warn(
"Method `_get_reference()` has been renamed to `get_reference()`. "
"The old name will be removed in DRF v3.14.",
RemovedInDRF314Warning, stacklevel=2
"The old name will be removed in DRF v3.15.",
RemovedInDRF315Warning, stacklevel=2
)
return self.get_reference(serializer)
2 changes: 1 addition & 1 deletion rest_framework/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField,
DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField,
HiddenField, HStoreField, IPAddressField, ImageField, IntegerField, JSONField,
ListField, ModelField, MultipleChoiceField, NullBooleanField, ReadOnlyField,
ListField, ModelField, MultipleChoiceField, ReadOnlyField,
RegexField, SerializerMethodField, SlugField, TimeField, URLField, UUIDField,
)
from rest_framework.relations import ( # NOQA # isort:skip
Expand Down
14 changes: 2 additions & 12 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,9 +679,9 @@ def test_disallow_unhashable_collection_types(self):
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 = {
'true': True,
Expand All @@ -706,16 +706,6 @@ class TestNullBooleanField(TestBooleanField):
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...

class TestCharField(FieldValues):
Expand Down