to respect formatting
+ white-space: pre; /* forces to respect formatting */
}
.main-container {
From 24a938abaadd98b5482bec33defd285625842342 Mon Sep 17 00:00:00 2001
From: Finn Gundlach
Date: Wed, 16 Jun 2021 15:53:29 +0200
Subject: [PATCH 023/450] Update documentation to include Django 3.2 as
supported version (#8037)
---
README.md | 2 +-
docs/index.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index ff76a5525d..fce275256e 100644
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@ There is a live example API for testing purposes, [available here][sandbox].
# Requirements
* Python (3.5, 3.6, 3.7, 3.8, 3.9)
-* Django (2.2, 3.0, 3.1)
+* Django (2.2, 3.0, 3.1, 3.2)
We **highly recommend** and only officially support the latest patch release of
each Python and Django series.
diff --git a/docs/index.md b/docs/index.md
index 530813684e..28e3302501 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -84,7 +84,7 @@ continued development by **[signing up for a paid plan][funding]**.
REST framework requires the following:
* Python (3.5, 3.6, 3.7, 3.8, 3.9)
-* Django (2.2, 3.0, 3.1)
+* Django (2.2, 3.0, 3.1, 3.2)
We **highly recommend** and only officially support the latest patch release of
each Python and Django series.
From e92016ac2e926483e05e296558fc3d1ea3279625 Mon Sep 17 00:00:00 2001
From: Adam Johnson
Date: Mon, 21 Jun 2021 11:33:43 +0100
Subject: [PATCH 024/450] Stop ignoring test outcome for Django 3.2 (#7927)
---
requirements/requirements-optionals.txt | 2 +-
setup.py | 1 +
tox.ini | 12 ------------
3 files changed, 2 insertions(+), 13 deletions(-)
diff --git a/requirements/requirements-optionals.txt b/requirements/requirements-optionals.txt
index 4cb0e54f4b..75b9ab4d60 100644
--- a/requirements/requirements-optionals.txt
+++ b/requirements/requirements-optionals.txt
@@ -2,7 +2,7 @@
coreapi==2.3.1
coreschema==0.0.4
django-filter>=2.4.0,<3.0
-django-guardian>=2.3.0,<2.4
+django-guardian>=2.4.0,<2.5
markdown==3.3;python_version>="3.6"
markdown==3.2.2;python_version=="3.5"
psycopg2-binary>=2.8.5,<2.9
diff --git a/setup.py b/setup.py
index e2a1c0222c..5fd4df20db 100755
--- a/setup.py
+++ b/setup.py
@@ -92,6 +92,7 @@ def get_version(package):
'Framework :: Django :: 2.2',
'Framework :: Django :: 3.0',
'Framework :: Django :: 3.1',
+ 'Framework :: Django :: 3.2',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
diff --git a/tox.ini b/tox.ini
index bf4de90d03..f23486a685 100644
--- a/tox.ini
+++ b/tox.ini
@@ -50,18 +50,6 @@ deps =
-rrequirements/requirements-testing.txt
-rrequirements/requirements-documentation.txt
-[testenv:py36-django32]
-ignore_outcome = true
-
-[testenv:py37-django32]
-ignore_outcome = true
-
-[testenv:py38-django32]
-ignore_outcome = true
-
-[testenv:py39-django32]
-ignore_outcome = true
-
[testenv:py38-djangomain]
ignore_outcome = true
From c8a9c856c25a1a360a91d2c7bc11e0dacfb9c3a4 Mon Sep 17 00:00:00 2001
From: Burak Kadir Er
Date: Mon, 28 Jun 2021 14:51:21 +0300
Subject: [PATCH 025/450] fix a small typo (#8060)
---
docs/api-guide/renderers.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md
index 954fb3bb98..7dbc5eee8f 100644
--- a/docs/api-guide/renderers.md
+++ b/docs/api-guide/renderers.md
@@ -105,7 +105,7 @@ The TemplateHTMLRenderer will create a `RequestContext`, using the `response.dat
---
-**Note:** When used with a view that makes use of a serializer the `Response` sent for rendering may not be a dictionay and will need to be wrapped in a dict before returning to allow the TemplateHTMLRenderer to render it. For example:
+**Note:** When used with a view that makes use of a serializer the `Response` sent for rendering may not be a dictionary and will need to be wrapped in a dict before returning to allow the TemplateHTMLRenderer to render it. For example:
```
response.data = {'results': response.data}
From d2977cff989f9b14f402ecf1e9235ee3d110977b Mon Sep 17 00:00:00 2001
From: Nikita Sobolev
Date: Mon, 28 Jun 2021 15:07:41 +0300
Subject: [PATCH 026/450] Fixes inconsistent headers in `serializer` docs
(#8056)
Some headers were using `.`, some - were not.
Now, all of them are the same with `.`, because it was easier to fix.
---
docs/api-guide/serializers.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md
index f05fe7e7e9..13c0c87104 100644
--- a/docs/api-guide/serializers.md
+++ b/docs/api-guide/serializers.md
@@ -605,13 +605,13 @@ For `ModelSerializer` this defaults to `PrimaryKeyRelatedField`.
For `HyperlinkedModelSerializer` this defaults to `serializers.HyperlinkedRelatedField`.
-### `serializer_url_field`
+### `.serializer_url_field`
The serializer field class that should be used for any `url` field on the serializer.
Defaults to `serializers.HyperlinkedIdentityField`
-### `serializer_choice_field`
+### `.serializer_choice_field`
The serializer field class that should be used for any choice fields on the serializer.
From 98e56e0327596db352b35fa3b3dc8355dc9bd030 Mon Sep 17 00:00:00 2001
From: Evgeny Panfilov
Date: Thu, 1 Jul 2021 17:04:44 +0300
Subject: [PATCH 027/450] fix empty string as a value for a validated
DecimalField (#8064) (#8067)
---
rest_framework/fields.py | 8 +++++---
tests/test_fields.py | 24 ++++++++++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index e4be54751d..bedc02b94d 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -1046,6 +1046,11 @@ def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=
'Invalid rounding option %s. Valid values for rounding are: %s' % (rounding, valid_roundings))
self.rounding = rounding
+ def validate_empty_values(self, data):
+ if smart_str(data).strip() == '' and self.allow_null:
+ return (True, None)
+ return super().validate_empty_values(data)
+
def to_internal_value(self, data):
"""
Validate that the input is a decimal number and return a Decimal
@@ -1063,9 +1068,6 @@ def to_internal_value(self, data):
try:
value = decimal.Decimal(data)
except decimal.DecimalException:
- if data == '' and self.allow_null:
- return None
-
self.fail('invalid')
if value.is_nan():
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 78a9effb8c..d99ca9c40d 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -1163,6 +1163,30 @@ class TestMinMaxDecimalField(FieldValues):
)
+class TestAllowEmptyStrDecimalFieldWithValidators(FieldValues):
+ """
+ Check that empty string ('', ' ') is acceptable value for the DecimalField
+ if allow_null=True and there are max/min validators
+ """
+ valid_inputs = {
+ None: None,
+ '': None,
+ ' ': None,
+ ' ': None,
+ 5: Decimal('5'),
+ '0': Decimal('0'),
+ '10': Decimal('10'),
+ }
+ invalid_inputs = {
+ -1: ['Ensure this value is greater than or equal to 0.'],
+ 11: ['Ensure this value is less than or equal to 10.'],
+ }
+ outputs = {
+ None: '',
+ }
+ field = serializers.DecimalField(max_digits=3, decimal_places=1, allow_null=True, min_value=0, max_value=10)
+
+
class TestNoMaxDigitsDecimalField(FieldValues):
field = serializers.DecimalField(
max_value=100, min_value=0,
From b215375125980114482779b36dd825775ef7e482 Mon Sep 17 00:00:00 2001
From: Nikhil Benesch
Date: Fri, 6 Aug 2021 05:10:58 -0400
Subject: [PATCH 028/450] Propagate nullability in ModelSerializer (#8116)
Propagate the nullability of underlying model fields in ModelSerializer
when those fields are marked as read only. This ensures the correct
generation of OpenAPI schemas.
Fix #8041.
---
rest_framework/serializers.py | 5 ++---
tests/schemas/test_openapi.py | 19 +++++++++++++++++++
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 49eec82591..9ea57f1aff 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -1326,9 +1326,8 @@ def include_extra_kwargs(self, kwargs, extra_kwargs):
"""
if extra_kwargs.get('read_only', False):
for attr in [
- 'required', 'default', 'allow_blank', 'allow_null',
- 'min_length', 'max_length', 'min_value', 'max_value',
- 'validators', 'queryset'
+ 'required', 'default', 'allow_blank', 'min_length',
+ 'max_length', 'min_value', 'max_value', 'validators', 'queryset'
]:
kwargs.pop(attr, None)
diff --git a/tests/schemas/test_openapi.py b/tests/schemas/test_openapi.py
index aef20670e6..daa035a3f3 100644
--- a/tests/schemas/test_openapi.py
+++ b/tests/schemas/test_openapi.py
@@ -2,6 +2,7 @@
import warnings
import pytest
+from django.db import models
from django.test import RequestFactory, TestCase, override_settings
from django.urls import path
from django.utils.translation import gettext_lazy as _
@@ -110,6 +111,24 @@ class Serializer(serializers.Serializer):
assert data['properties']['default_false']['default'] is False, "default must be false"
assert 'default' not in data['properties']['without_default'], "default must not be defined"
+ def test_nullable_fields(self):
+ class Model(models.Model):
+ rw_field = models.CharField(null=True)
+ ro_field = models.CharField(null=True)
+
+ class Serializer(serializers.ModelSerializer):
+ class Meta:
+ model = Model
+ fields = ["rw_field", "ro_field"]
+ read_only_fields = ["ro_field"]
+
+ inspector = AutoSchema()
+
+ data = inspector.map_serializer(Serializer())
+ assert data['properties']['rw_field']['nullable'], "rw_field nullable must be true"
+ assert data['properties']['ro_field']['nullable'], "ro_field nullable must be true"
+ assert data['properties']['ro_field']['readOnly'], "ro_field read_only must be true"
+
@pytest.mark.skipif(uritemplate is None, reason='uritemplate not installed.')
class TestOperationIntrospection(TestCase):
From fdb49314754ff13d91c6eec7ccdb8ece52bea9eb Mon Sep 17 00:00:00 2001
From: Aarni Koskela
Date: Fri, 6 Aug 2021 12:14:52 +0300
Subject: [PATCH 029/450] Make Field constructors keyword-only (#7632)
---
rest_framework/fields.py | 46 ++++++++++++++++++++--------------------
tests/test_fields.py | 5 +++++
2 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index bedc02b94d..5cafed5556 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -320,7 +320,7 @@ class Field:
default_empty_html = empty
initial = None
- def __init__(self, read_only=False, write_only=False,
+ def __init__(self, *, read_only=False, write_only=False,
required=None, default=empty, initial=empty, source=None,
label=None, help_text=None, style=None,
error_messages=None, validators=None, allow_null=False):
@@ -1163,14 +1163,14 @@ class DateTimeField(Field):
}
datetime_parser = datetime.datetime.strptime
- def __init__(self, format=empty, input_formats=None, default_timezone=None, *args, **kwargs):
+ def __init__(self, format=empty, input_formats=None, default_timezone=None, **kwargs):
if format is not empty:
self.format = format
if input_formats is not None:
self.input_formats = input_formats
if default_timezone is not None:
self.timezone = default_timezone
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def enforce_timezone(self, value):
"""
@@ -1249,12 +1249,12 @@ class DateField(Field):
}
datetime_parser = datetime.datetime.strptime
- def __init__(self, format=empty, input_formats=None, *args, **kwargs):
+ def __init__(self, format=empty, input_formats=None, **kwargs):
if format is not empty:
self.format = format
if input_formats is not None:
self.input_formats = input_formats
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def to_internal_value(self, value):
input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS)
@@ -1315,12 +1315,12 @@ class TimeField(Field):
}
datetime_parser = datetime.datetime.strptime
- def __init__(self, format=empty, input_formats=None, *args, **kwargs):
+ def __init__(self, format=empty, input_formats=None, **kwargs):
if format is not empty:
self.format = format
if input_formats is not None:
self.input_formats = input_formats
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def to_internal_value(self, value):
input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS)
@@ -1470,9 +1470,9 @@ class MultipleChoiceField(ChoiceField):
}
default_empty_html = []
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
self.allow_empty = kwargs.pop('allow_empty', True)
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def get_value(self, dictionary):
if self.field_name not in dictionary:
@@ -1529,12 +1529,12 @@ class FileField(Field):
'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'),
}
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
self.max_length = kwargs.pop('max_length', None)
self.allow_empty_file = kwargs.pop('allow_empty_file', False)
if 'use_url' in kwargs:
self.use_url = kwargs.pop('use_url')
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def to_internal_value(self, data):
try:
@@ -1578,9 +1578,9 @@ class ImageField(FileField):
),
}
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
self._DjangoImageField = kwargs.pop('_DjangoImageField', DjangoImageField)
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def to_internal_value(self, data):
# Image validation is a bit grungy, so we'll just outright
@@ -1595,8 +1595,8 @@ def to_internal_value(self, data):
# Composite field types...
class _UnvalidatedField(Field):
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
self.allow_blank = True
self.allow_null = True
@@ -1617,7 +1617,7 @@ class ListField(Field):
'max_length': _('Ensure this field has no more than {max_length} elements.')
}
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
self.child = kwargs.pop('child', copy.deepcopy(self.child))
self.allow_empty = kwargs.pop('allow_empty', True)
self.max_length = kwargs.pop('max_length', None)
@@ -1629,7 +1629,7 @@ def __init__(self, *args, **kwargs):
"Remove `source=` from the field declaration."
)
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
self.child.bind(field_name='', parent=self)
if self.max_length is not None:
message = lazy_format(self.error_messages['max_length'], max_length=self.max_length)
@@ -1694,7 +1694,7 @@ class DictField(Field):
'empty': _('This dictionary may not be empty.'),
}
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
self.child = kwargs.pop('child', copy.deepcopy(self.child))
self.allow_empty = kwargs.pop('allow_empty', True)
@@ -1704,7 +1704,7 @@ def __init__(self, *args, **kwargs):
"Remove `source=` from the field declaration."
)
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
self.child.bind(field_name='', parent=self)
def get_value(self, dictionary):
@@ -1753,8 +1753,8 @@ def run_child_validation(self, data):
class HStoreField(DictField):
child = CharField(allow_blank=True, allow_null=True)
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
assert isinstance(self.child, CharField), (
"The `child` argument must be an instance of `CharField`, "
"as the hstore extension stores values as strings."
@@ -1769,11 +1769,11 @@ class JSONField(Field):
# Workaround for isinstance calls when importing the field isn't possible
_is_jsonfield = True
- def __init__(self, *args, **kwargs):
+ def __init__(self, **kwargs):
self.binary = kwargs.pop('binary', False)
self.encoder = kwargs.pop('encoder', None)
self.decoder = kwargs.pop('decoder', None)
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def get_value(self, dictionary):
if html.is_html_input(dictionary) and self.field_name in dictionary:
diff --git a/tests/test_fields.py b/tests/test_fields.py
index d99ca9c40d..2d4cc44ae0 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -2010,6 +2010,11 @@ def test_collection_types_are_invalid_input(self):
field.to_internal_value(input_value)
assert exc_info.value.detail == ['Expected a list of items but got type "dict".']
+ def test_constructor_misuse_raises(self):
+ # Test that `ListField` can only be instantiated with keyword arguments
+ with pytest.raises(TypeError):
+ serializers.ListField(serializers.CharField())
+
class TestNestedListField(FieldValues):
"""
From 2942590ee3d3596683405dcdb1017e1833f5cb02 Mon Sep 17 00:00:00 2001
From: Ma77heus <58952630+MattheusHenrique@users.noreply.github.com>
Date: Fri, 6 Aug 2021 12:39:58 -0300
Subject: [PATCH 030/450] fix: broken cite (#8086)
Co-authored-by: MattheusHenrique
---
docs/api-guide/renderers.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md
index 7dbc5eee8f..f13b7ba946 100644
--- a/docs/api-guide/renderers.md
+++ b/docs/api-guide/renderers.md
@@ -528,7 +528,7 @@ Comma-separated values are a plain-text tabular data format, that can be easily
[Rest Framework Latex] provides a renderer that outputs PDFs using Laulatex. It is maintained by [Pebble (S/F Software)][mypebble].
-[cite]: https://docs.djangoproject.com/en/stable/stable/template-response/#the-rendering-process
+[cite]: https://docs.djangoproject.com/en/stable/ref/template-response/#the-rendering-process
[conneg]: content-negotiation.md
[html-and-forms]: ../topics/html-and-forms.md
[browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers
From cba24464e8f63377627f3016df88ee74d11a817d Mon Sep 17 00:00:00 2001
From: Paul Wayper
Date: Sat, 7 Aug 2021 01:45:15 +1000
Subject: [PATCH 031/450] Botbot has been acquired, all paths now point to
startupresources (#8050)
Signed-off-by: Paul Wayper
---
docs/index.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/docs/index.md b/docs/index.md
index 28e3302501..ccbaf73731 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -186,7 +186,7 @@ Framework.
## Support
-For support please see the [REST framework discussion group][group], try the `#restframework` channel on `irc.freenode.net`, search [the IRC archives][botbot], or raise a question on [Stack Overflow][stack-overflow], making sure to include the ['django-rest-framework'][django-rest-framework-tag] tag.
+For support please see the [REST framework discussion group][group], try the `#restframework` channel on `irc.freenode.net`, or raise a question on [Stack Overflow][stack-overflow], making sure to include the ['django-rest-framework'][django-rest-framework-tag] tag.
For priority support please sign up for a [professional or premium sponsorship plan](https://fund.django-rest-framework.org/topics/funding/).
@@ -257,7 +257,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[funding]: community/funding.md
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
-[botbot]: https://botbot.me/freenode/restframework/
[stack-overflow]: https://stackoverflow.com/
[django-rest-framework-tag]: https://stackoverflow.com/questions/tagged/django-rest-framework
[security-mail]: mailto:rest-framework-security@googlegroups.com
From c4404f3d5d2df2a5c7450517b48c4e6dfeb3c89e Mon Sep 17 00:00:00 2001
From: Paul Wayper
Date: Sat, 7 Aug 2021 01:46:26 +1000
Subject: [PATCH 032/450] We now use Libera.chat rather than Freenode for IRC
(#8049)
Signed-off-by: Paul Wayper
Co-authored-by: Tom Christie
---
README.md | 2 +-
docs/index.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index fce275256e..b8d8ca61b1 100644
--- a/README.md
+++ b/README.md
@@ -168,7 +168,7 @@ Or to create a new user:
Full documentation for the project is available at [https://www.django-rest-framework.org/][docs].
-For questions and support, use the [REST framework discussion group][group], or `#restframework` on freenode IRC.
+For questions and support, use the [REST framework discussion group][group], or `#restframework` on libera.chat IRC.
You may also want to [follow the author on Twitter][twitter].
diff --git a/docs/index.md b/docs/index.md
index ccbaf73731..641800b93c 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -186,7 +186,7 @@ Framework.
## Support
-For support please see the [REST framework discussion group][group], try the `#restframework` channel on `irc.freenode.net`, or raise a question on [Stack Overflow][stack-overflow], making sure to include the ['django-rest-framework'][django-rest-framework-tag] tag.
+For support please see the [REST framework discussion group][group], try the `#restframework` channel on `irc.libera.chat`, or raise a question on [Stack Overflow][stack-overflow], making sure to include the ['django-rest-framework'][django-rest-framework-tag] tag.
For priority support please sign up for a [professional or premium sponsorship plan](https://fund.django-rest-framework.org/topics/funding/).
From b824b33dc3a3facad3ef2b41fbe02ab2a7578bc3 Mon Sep 17 00:00:00 2001
From: Thomas Grainger
Date: Fri, 6 Aug 2021 16:46:57 +0100
Subject: [PATCH 033/450] add changelog project_url (#8085)
---
setup.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/setup.py b/setup.py
index 5fd4df20db..d755a00fe2 100755
--- a/setup.py
+++ b/setup.py
@@ -109,6 +109,7 @@ def get_version(package):
project_urls={
'Funding': 'https://fund.django-rest-framework.org/topics/funding/',
'Source': 'https://github.com/encode/django-rest-framework',
+ 'Changelog': 'https://www.django-rest-framework.org/community/release-notes/',
},
)
From e95e91ccf2065cbf474892b73ebd5790e5a4ae14 Mon Sep 17 00:00:00 2001
From: Ben Hampson <77866043+Ben-Hampson@users.noreply.github.com>
Date: Fri, 6 Aug 2021 17:49:41 +0200
Subject: [PATCH 034/450] Use correct link for httpie (#8005)
Before it was linking to a fork of a fork of httpie. I've changed it to the right URL.
---
docs/tutorial/1-serialization.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md
index 85d8676b1d..908b7474a0 100644
--- a/docs/tutorial/1-serialization.md
+++ b/docs/tutorial/1-serialization.md
@@ -374,5 +374,5 @@ We'll see how we can start to improve things in [part 2 of the tutorial][tut-2].
[sandbox]: https://restframework.herokuapp.com/
[venv]: https://docs.python.org/3/library/venv.html
[tut-2]: 2-requests-and-responses.md
-[httpie]: https://github.com/jakubroztocil/httpie#installation
+[httpie]: https://github.com/httpie/httpie#installation
[curl]: https://curl.haxx.se/
From cdd53c7de912d5868c96f4e3883df248a3e6341d Mon Sep 17 00:00:00 2001
From: juliangeissler <81534590+juliangeissler@users.noreply.github.com>
Date: Sun, 8 Aug 2021 15:45:00 +0200
Subject: [PATCH 035/450] Update Tutorial - Relationships & Hyperlinked APIs
(#7950)
unnecessary import, because it is already added in the previous section
---
docs/tutorial/5-relationships-and-hyperlinked-apis.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md
index b0f3380859..f999fdf507 100644
--- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md
+++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md
@@ -31,7 +31,6 @@ The other thing we need to consider when creating the code highlight view is tha
Instead of using a concrete generic view, we'll use the base class for representing instances, and create our own `.get()` method. In your `snippets/views.py` add:
from rest_framework import renderers
- from rest_framework.response import Response
class SnippetHighlight(generics.GenericAPIView):
queryset = Snippet.objects.all()
From c5d9144aef1144825942ddffe0a6af23102ef44a Mon Sep 17 00:00:00 2001
From: Mark <33526445+mark-gold@users.noreply.github.com>
Date: Wed, 11 Aug 2021 13:30:09 +0300
Subject: [PATCH 036/450] fix typo (#8122)
Co-authored-by: mgold
---
docs/api-guide/validators.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index 4451489d4d..76dcb0d541 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -238,7 +238,7 @@ In the case of update operations on *nested* serializers there's no way of
applying this exclusion, because the instance is not available.
Again, you'll probably want to explicitly remove the validator from the
-serializer class, and write the code the for the validation constraint
+serializer class, and write the code for the validation constraint
explicitly, in a `.validate()` method, or in the view.
## Debugging complex cases
From c927053d4b99ada6b3fd5d70c6536554ff5fe8c0 Mon Sep 17 00:00:00 2001
From: jefcolbi
Date: Tue, 31 Aug 2021 12:51:47 +0100
Subject: [PATCH 037/450] Replacing django-rest-auth with dj-rest-auth (#8146)
---
docs/community/third-party-packages.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/community/third-party-packages.md b/docs/community/third-party-packages.md
index e53fc3d50c..933244a6a9 100644
--- a/docs/community/third-party-packages.md
+++ b/docs/community/third-party-packages.md
@@ -54,7 +54,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
* [hawkrest][hawkrest] - Provides Hawk HTTP Authorization.
* [djangorestframework-httpsignature][djangorestframework-httpsignature] - Provides an easy to use HTTP Signature Authentication mechanism.
* [djoser][djoser] - Provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation.
-* [django-rest-auth][django-rest-auth] - Provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc.
+* [dj-rest-auth][dj-rest-auth] - Provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc.
* [drf-oidc-auth][drf-oidc-auth] - Implements OpenID Connect token authentication for DRF.
* [drfpasswordless][drfpasswordless] - Adds (Medium, Square Cash inspired) passwordless logins and signups via email and mobile numbers.
* [django-rest-authemail][django-rest-authemail] - Provides a RESTful API for user signup and authentication using email addresses.
@@ -193,7 +193,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[gaiarestframework]: https://github.com/AppsFuel/gaiarestframework
[drf-extensions]: https://github.com/chibisov/drf-extensions
[ember-django-adapter]: https://github.com/dustinfarris/ember-django-adapter
-[django-rest-auth]: https://github.com/Tivix/django-rest-auth/
+[dj-rest-auth]: https://github.com/iMerica/dj-rest-auth
[django-versatileimagefield]: https://github.com/WGBH/django-versatileimagefield
[django-versatileimagefield-drf-docs]:https://django-versatileimagefield.readthedocs.io/en/latest/drf_integration.html
[drf-tracking]: https://github.com/aschn/drf-tracking
From 88666629a70f5c3fbe31e11aecd9817338de9c92 Mon Sep 17 00:00:00 2001
From: Asif Saif Uddin
Date: Tue, 31 Aug 2021 18:56:08 +0600
Subject: [PATCH 038/450] stop testing django 3.0 as its EOL (#8136)
---
tox.ini | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/tox.ini b/tox.ini
index f23486a685..25f8418219 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,6 @@
[tox]
envlist =
{py35,py36,py37}-django22,
- {py36,py37,py38}-django30,
{py36,py37,py38,py39}-django31,
{py36,py37,py38,py39}-django32,
{py38,py39}-djangomain,
@@ -10,7 +9,6 @@ envlist =
[travis:env]
DJANGO =
2.2: django22
- 3.0: django30
3.1: django31
3.2: django32
main: djangomain
@@ -23,9 +21,8 @@ setenv =
PYTHONWARNINGS=once
deps =
django22: Django>=2.2,<3.0
- django30: Django>=3.0,<3.1
django31: Django>=3.1,<3.2
- django32: Django>=3.2a1,<4.0
+ django32: Django>=3.2,<4.0
djangomain: https://github.com/django/django/archive/main.tar.gz
-rrequirements/requirements-testing.txt
-rrequirements/requirements-optionals.txt
From 6b392a46ea025148a24ce665e9c18e4386dde8fa Mon Sep 17 00:00:00 2001
From: Aditya Mitra <55396651+aditya-mitra@users.noreply.github.com>
Date: Tue, 31 Aug 2021 18:27:02 +0530
Subject: [PATCH 039/450] [FIX] Typo in api-guide/authentication (#8144)
---
docs/api-guide/authentication.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md
index 60544079f1..57bbaeb679 100644
--- a/docs/api-guide/authentication.md
+++ b/docs/api-guide/authentication.md
@@ -13,7 +13,7 @@ Authentication is the mechanism of associating an incoming request with a set of
REST framework provides several authentication schemes out of the box, and also allows you to implement custom schemes.
-Authentication is always run at the very start of the view, before the permission and throttling checks occur, and before any other code is allowed to proceed.
+Authentication always runs at the very start of the view, before the permission and throttling checks occur, and before any other code is allowed to proceed.
The `request.user` property will typically be set to an instance of the `contrib.auth` package's `User` class.
From 4632b5daaed5a71a1be3e7d412a7f9a2e5520b90 Mon Sep 17 00:00:00 2001
From: Ryan Nowakowski
Date: Tue, 31 Aug 2021 08:18:49 -0500
Subject: [PATCH 040/450] Fix subtitle of schemas for filtering (#8145)
Fix a likely copy/paste error
---
docs/api-guide/filtering.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md
index 478e3bcf95..3541388ca2 100644
--- a/docs/api-guide/filtering.md
+++ b/docs/api-guide/filtering.md
@@ -335,7 +335,7 @@ Generic filters may also present an interface in the browsable API. To do so you
The method should return a rendered HTML string.
-## Pagination & schemas
+## Filtering & schemas
You can also make the filter controls available to the schema autogeneration
that REST framework provides, by implementing a `get_schema_fields()` method. This method should have the following signature:
From cb206e4701dd67f859c015bea111d0e77e364c4a Mon Sep 17 00:00:00 2001
From: Juan Benitez
Date: Fri, 3 Sep 2021 07:00:23 -0500
Subject: [PATCH 041/450] fix: change View class to Throttle class on
SimpleRateThrottle Docstring (#8147)
---
rest_framework/throttling.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rest_framework/throttling.py b/rest_framework/throttling.py
index 0ba2ba66b1..e262b886bc 100644
--- a/rest_framework/throttling.py
+++ b/rest_framework/throttling.py
@@ -52,7 +52,7 @@ class SimpleRateThrottle(BaseThrottle):
A simple cache implementation, that only requires `.get_cache_key()`
to be overridden.
- The rate (requests / seconds) is set by a `rate` attribute on the View
+ The rate (requests / seconds) is set by a `rate` attribute on the Throttle
class. The attribute is a string of the form 'number_of_requests/period'.
Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')
From 96001c5de61b5fe7c083bdd8e5810105e3575014 Mon Sep 17 00:00:00 2001
From: Anthony Randall
Date: Fri, 3 Sep 2021 06:23:19 -0600
Subject: [PATCH 042/450] Added an article - implementing rest apis with
embedded privacy from doordash engineering blog (#7956)
* Update tutorials-and-resources.md
* Update tutorials-and-resources.md
---
docs/community/tutorials-and-resources.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/community/tutorials-and-resources.md b/docs/community/tutorials-and-resources.md
index dae292f50c..23faf79128 100644
--- a/docs/community/tutorials-and-resources.md
+++ b/docs/community/tutorials-and-resources.md
@@ -76,6 +76,7 @@ There are a wide range of resources available for learning and using Django REST
* [Chatbot Using Django REST Framework + api.ai + SlackāāāPart 1/3][chatbot-using-drf-part1]
* [New Django Admin with DRF and EmberJS... What are the News?][new-django-admin-with-drf-and-emberjs]
* [Blog posts about Django REST Framework][medium-django-rest-framework]
+* [Implementing Rest APIs With Embedded Privacy][doordash-implementing-rest-apis]
### Documentations
* [Classy Django REST Framework][cdrf.co]
@@ -128,3 +129,4 @@ Want your Django REST Framework talk/tutorial/article to be added to our website
[anna-email]: mailto:anna@django-rest-framework.org
[pycon-us-2017]: https://www.youtube.com/watch?v=Rk6MHZdust4
[django-rest-react-valentinog]: https://www.valentinog.com/blog/tutorial-api-django-rest-react/
+[doordash-implementing-rest-apis]: https://doordash.engineering/2013/10/07/implementing-rest-apis-with-embedded-privacy/
From 655e803adfb19b8cb5b94a4895f1baffed55a958 Mon Sep 17 00:00:00 2001
From: Peter Uittenbroek
Date: Fri, 3 Sep 2021 15:37:03 +0200
Subject: [PATCH 043/450] #7157: Fix RemoteUserAuthentication calling django
authenticate with request argument (#7158)
---
rest_framework/authentication.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py
index 9111007c09..382abf1580 100644
--- a/rest_framework/authentication.py
+++ b/rest_framework/authentication.py
@@ -227,6 +227,6 @@ class RemoteUserAuthentication(BaseAuthentication):
header = "REMOTE_USER"
def authenticate(self, request):
- user = authenticate(remote_user=request.META.get(self.header))
+ user = authenticate(request=request, remote_user=request.META.get(self.header))
if user and user.is_active:
return (user, None)
From 9716b1b6b7779543c134856e59f1c1393963e46f Mon Sep 17 00:00:00 2001
From: Ivan Trushin <33528037+WannaFight@users.noreply.github.com>
Date: Mon, 6 Sep 2021 14:18:13 +0300
Subject: [PATCH 044/450] Fix arguments (#7995)
`path()` has no argument `namespace`, it has `name` argument
---
docs/tutorial/quickstart.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md
index ee839790f1..e19577f617 100644
--- a/docs/tutorial/quickstart.md
+++ b/docs/tutorial/quickstart.md
@@ -126,7 +126,7 @@ Okay, now let's wire up the API URLs. On to `tutorial/urls.py`...
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('', include(router.urls)),
- path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
+ path('api-auth/', include('rest_framework.urls', name='rest_framework'))
]
Because we're using viewsets instead of views, we can automatically generate the URL conf for our API, by simply registering the viewsets with a router class.
From 9ce541e90990307e06da1b7f5a2576406366a5e5 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Mon, 6 Sep 2021 12:19:20 +0100
Subject: [PATCH 045/450] Revert "Fix arguments (#7995)" (#8156)
This reverts commit 9716b1b6b7779543c134856e59f1c1393963e46f.
---
docs/tutorial/quickstart.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md
index e19577f617..ee839790f1 100644
--- a/docs/tutorial/quickstart.md
+++ b/docs/tutorial/quickstart.md
@@ -126,7 +126,7 @@ Okay, now let's wire up the API URLs. On to `tutorial/urls.py`...
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('', include(router.urls)),
- path('api-auth/', include('rest_framework.urls', name='rest_framework'))
+ path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Because we're using viewsets instead of views, we can automatically generate the URL conf for our API, by simply registering the viewsets with a router class.
From 73f3325f80a381d1d62ab1b84956295963f445ed Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Fri, 10 Sep 2021 11:32:27 +0100
Subject: [PATCH 046/450] Update stream.io link (#8161)
---
README.md | 2 +-
docs/index.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index b8d8ca61b1..e3bcc2a1c2 100644
--- a/README.md
+++ b/README.md
@@ -197,7 +197,7 @@ Please see the [security policy][security-policy].
[bitio-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/bitio-readme.png
[sentry-url]: https://getsentry.com/welcome/
-[stream-url]: https://getstream.io/try-the-api/?utm_source=drf&utm_medium=banner&utm_campaign=drf
+[stream-url]: https://getstream.io/?utm_source=drf&utm_medium=sponsorship&utm_content=developer
[rollbar-url]: https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial
[esg-url]: https://software.esg-usa.com/
[retool-url]: https://retool.com/?utm_source=djangorest&utm_medium=sponsorship
diff --git a/docs/index.md b/docs/index.md
index 641800b93c..9b667c6691 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -75,7 +75,7 @@ continued development by **[signing up for a paid plan][funding]**.
-*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), [ESG](https://software.esg-usa.com/), [Rollbar](https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial), [Cadre](https://cadre.com), [Kloudless](https://hubs.ly/H0f30Lf0), [Lights On Software](https://lightsonsoftware.com), [Retool](https://retool.com/?utm_source=djangorest&utm_medium=sponsorship), and [bit.io](https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship).*
+*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=sponsorship&utm_content=developer), [ESG](https://software.esg-usa.com/), [Rollbar](https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial), [Cadre](https://cadre.com), [Kloudless](https://hubs.ly/H0f30Lf0), [Lights On Software](https://lightsonsoftware.com), [Retool](https://retool.com/?utm_source=djangorest&utm_medium=sponsorship), and [bit.io](https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship).*
---
From 761f56ef4025543e9cf39346d25641305e7d957d Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Fri, 10 Sep 2021 14:45:06 +0100
Subject: [PATCH 047/450] Update stream.io link
---
docs/index.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/index.md b/docs/index.md
index 9b667c6691..f000d2e093 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -67,7 +67,7 @@ continued development by **[signing up for a paid plan][funding]**.
-*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=sponsorship&utm_content=developer), [ESG](https://software.esg-usa.com/), [Rollbar](https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial), [Cadre](https://cadre.com), [Kloudless](https://hubs.ly/H0f30Lf0), [Lights On Software](https://lightsonsoftware.com), [Retool](https://retool.com/?utm_source=djangorest&utm_medium=sponsorship), and [bit.io](https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship).*
+*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=sponsorship&utm_content=developer), [ESG](https://software.esg-usa.com/), [Rollbar](https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial), [Cadre](https://cadre.com), [Kloudless](https://hubs.ly/H0f30Lf0), [Lights On Software](https://lightsonsoftware.com), [Retool](https://retool.com/?utm_source=djangorest&utm_medium=sponsorship), [bit.io](https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship), and [bit.io](https://posthog.com?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship).*
---
From 6ea95b6ad1bc0d4a4234a267b1ba32701878c6bb Mon Sep 17 00:00:00 2001
From: thetarby <45286577+thetarby@users.noreply.github.com>
Date: Tue, 5 Oct 2021 17:33:55 +0300
Subject: [PATCH 058/450] Highlight `select_related` and `prefetch_related`
usage in documentation (#7610)
* docs updated to highlight use of select_related and prefetch related to avoid n+1 problems
* Apply suggestions from code review
cosmetic changes
Co-authored-by: Xavier Ordoquy
* cosmetic changes
Co-authored-by: Xavier Ordoquy
---
docs/api-guide/fields.md | 10 +++++++++-
docs/api-guide/generic-views.md | 7 +++++++
docs/api-guide/relations.md | 31 +++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md
index b986009f9b..5b9688dcab 100644
--- a/docs/api-guide/fields.md
+++ b/docs/api-guide/fields.md
@@ -78,7 +78,14 @@ Defaults to `False`
### `source`
-The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`. When serializing fields with dotted notation, it may be necessary to provide a `default` value if any object is not present or is empty during attribute traversal.
+The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`.
+
+When serializing fields with dotted notation, it may be necessary to provide a `default` value if any object is not present or is empty during attribute traversal. Beware of possible n+1 problems when using source attribute if you are accessing a relational orm model. For example:
+
+ class CommentSerializer(serializers.Serializer):
+ email = serializers.EmailField(source="user.email")
+
+would require user object to be fetched from database when it is not prefetched. If that is not wanted, be sure to be using `prefetch_related` and `select_related` methods appropriately. For more information about the methods refer to [django documentation][django-docs-select-related].
The value `source='*'` has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.
@@ -855,3 +862,4 @@ The [django-rest-framework-hstore][django-rest-framework-hstore] package provide
[django-hstore]: https://github.com/djangonauts/django-hstore
[python-decimal-rounding-modes]: https://docs.python.org/3/library/decimal.html#rounding-modes
[django-current-timezone]: https://docs.djangoproject.com/en/stable/topics/i18n/timezones/#default-time-zone-and-current-time-zone
+[django-docs-select-related]: https://docs.djangoproject.com/en/3.1/ref/models/querysets/#django.db.models.query.QuerySet.select_related
diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md
index afc2cab563..fbafec93ad 100644
--- a/docs/api-guide/generic-views.md
+++ b/docs/api-guide/generic-views.md
@@ -96,6 +96,12 @@ For example:
user = self.request.user
return user.accounts.all()
+---
+
+**Note:** If the serializer_class used in the generic view spans orm relations, leading to an n+1 problem, you could optimize your queryset in this method using `select_related` and `prefetch_related`. To get more information about n+1 problem and use cases of the mentioned methods refer to related section in [django documentation][django-docs-select-related].
+
+---
+
#### `get_object(self)`
Returns an object instance that should be used for detail views. Defaults to using the `lookup_field` parameter to filter the base queryset.
@@ -389,3 +395,4 @@ The following third party packages provide additional generic view implementatio
[UpdateModelMixin]: #updatemodelmixin
[DestroyModelMixin]: #destroymodelmixin
[django-rest-multiple-models]: https://github.com/MattBroach/DjangoRestMultipleModels
+[django-docs-select-related]: https://docs.djangoproject.com/en/3.1/ref/models/querysets/#django.db.models.query.QuerySet.select_related
\ No newline at end of file
diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md
index f444125cff..4547253b0a 100644
--- a/docs/api-guide/relations.md
+++ b/docs/api-guide/relations.md
@@ -17,6 +17,37 @@ Relational fields are used to represent model relationships. They can be applie
---
+---
+
+**Note:** REST Framework does not attempt to automatically optimize querysets passed to serializers in terms of `select_related` and `prefetch_related` since it would be too much magic. A serializer with a field spanning an orm relation through its source attribute could require an additional database hit to fetch related object from the database. It is the programmer's responsibility to optimize queries to avoid additional database hits which could occur while using such a serializer.
+
+For example, the following serializer would lead to a database hit each time evaluating the tracks field if it is not prefetched:
+
+ class AlbumSerializer(serializers.ModelSerializer):
+ tracks = serializers.SlugRelatedField(
+ many=True,
+ read_only=True,
+ slug_field='title'
+ )
+
+ class Meta:
+ model = Album
+ fields = ['album_name', 'artist', 'tracks']
+
+ # For each album object, tracks should be fetched from database
+ qs = Album.objects.all()
+ print(AlbumSerializer(qs, many=True).data)
+
+If `AlbumSerializer` is used to serialize a fairly large queryset with `many=True` then it could be a serious performance problem. Optimizing the queryset passed to `AlbumSerializer` with:
+
+ qs = Album.objects.prefetch_related('tracks')
+ # No additional database hits required
+ print(AlbumSerializer(qs, many=True).data)
+
+would solve the issue.
+
+---
+
#### Inspecting relationships.
When using the `ModelSerializer` class, serializer fields and relationships will be automatically generated for you. Inspecting these automatically generated fields can be a useful tool for determining how to customize the relationship style.
From 53a0585dacea328ce74083f0da0dea10c4df03e5 Mon Sep 17 00:00:00 2001
From: Edmund <2623895+edmundlam@users.noreply.github.com>
Date: Thu, 7 Oct 2021 04:09:00 -0400
Subject: [PATCH 059/450] Update permissions.md to fix garden path sentences
(#8206)
---
docs/api-guide/permissions.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md
index 6912c375c2..19bc0e66ae 100644
--- a/docs/api-guide/permissions.md
+++ b/docs/api-guide/permissions.md
@@ -24,9 +24,9 @@ A slightly less strict style of permission would be to allow full access to auth
Permissions in REST framework are always defined as a list of permission classes.
Before running the main body of the view each permission in the list is checked.
-If any permission check fails an `exceptions.PermissionDenied` or `exceptions.NotAuthenticated` exception will be raised, and the main body of the view will not run.
+If any permission check fails, an `exceptions.PermissionDenied` or `exceptions.NotAuthenticated` exception will be raised, and the main body of the view will not run.
-When the permissions checks fail either a "403 Forbidden" or a "401 Unauthorized" response will be returned, according to the following rules:
+When the permission checks fail, either a "403 Forbidden" or a "401 Unauthorized" response will be returned, according to the following rules:
* The request was successfully authenticated, but permission was denied. *— An HTTP 403 Forbidden response will be returned.*
* The request was not successfully authenticated, and the highest priority authentication class *does not* use `WWW-Authenticate` headers. *— An HTTP 403 Forbidden response will be returned.*
From ddc5cd7e4b5f4bf250afd412b314af6728ea1726 Mon Sep 17 00:00:00 2001
From: Uzair Ali <72073401+uzair-ali10@users.noreply.github.com>
Date: Thu, 7 Oct 2021 20:22:44 +0530
Subject: [PATCH 060/450] Imported Response (#8207)
---
docs/api-guide/views.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/api-guide/views.md b/docs/api-guide/views.md
index 2224c1f3a5..878a291b22 100644
--- a/docs/api-guide/views.md
+++ b/docs/api-guide/views.md
@@ -145,6 +145,7 @@ REST framework also allows you to work with regular function based views. It pr
The core of this functionality is the `api_view` decorator, which takes a list of HTTP methods that your view should respond to. For example, this is how you would write a very simple view that just manually returns some data:
from rest_framework.decorators import api_view
+ from rest_framework.response import Response
@api_view()
def hello_world(request):
From 00cd4ef864a8bf6d6c90819a983017070f9f08a5 Mon Sep 17 00:00:00 2001
From: rgermain
Date: Fri, 15 Oct 2021 16:13:20 +0200
Subject: [PATCH 061/450] add third packages nested-multipart-parser (#8208)
---
docs/community/third-party-packages.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/community/third-party-packages.md b/docs/community/third-party-packages.md
index 933244a6a9..e25421f503 100644
--- a/docs/community/third-party-packages.md
+++ b/docs/community/third-party-packages.md
@@ -106,6 +106,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
* [djangorestframework-msgpack][djangorestframework-msgpack] - Provides MessagePack renderer and parser support.
* [djangorestframework-jsonapi][djangorestframework-jsonapi] - Provides a parser, renderer, serializers, and other tools to help build an API that is compliant with the jsonapi.org spec.
* [djangorestframework-camel-case][djangorestframework-camel-case] - Provides camel case JSON renderers and parsers.
+* [nested-multipart-parser][nested-multipart-parser] - Provides nested parser for http multipart request
### Renderers
@@ -183,6 +184,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[wq.db.rest]: https://wq.io/docs/about-rest
[djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack
[djangorestframework-camel-case]: https://github.com/vbabiy/djangorestframework-camel-case
+[nested-multipart-parser]: https://github.com/remigermain/nested-multipart-parser
[djangorestframework-csv]: https://github.com/mjumbewu/django-rest-framework-csv
[drf_ujson2]: https://github.com/Amertz08/drf_ujson2
[rest-pandas]: https://github.com/wq/django-rest-pandas
From 781890b7df88086d9cba07904e53db346ec4a715 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Lavoie?=
Date: Mon, 8 Nov 2021 03:59:32 -0600
Subject: [PATCH 062/450] docs(api-guide-testing): Fix typo 'CRSF' and plural
of word (#8238)
---
docs/api-guide/testing.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md
index 73de68a76b..62eb8dd1a5 100644
--- a/docs/api-guide/testing.md
+++ b/docs/api-guide/testing.md
@@ -234,7 +234,7 @@ If you're using `SessionAuthentication` then you'll need to include a CSRF token
for any `POST`, `PUT`, `PATCH` or `DELETE` requests.
You can do so by following the same flow that a JavaScript based client would use.
-First make a `GET` request in order to obtain a CRSF token, then present that
+First, make a `GET` request in order to obtain a CSRF token, then present that
token in the following request.
For example...
@@ -259,7 +259,7 @@ With careful usage both the `RequestsClient` and the `CoreAPIClient` provide
the ability to write test cases that can run either in development, or be run
directly against your staging server or production environment.
-Using this style to create basic tests of a few core piece of functionality is
+Using this style to create basic tests of a few core pieces of functionality is
a powerful way to validate your live service. Doing so may require some careful
attention to setup and teardown to ensure that the tests run in a way that they
do not directly affect customer data.
From 060a3b632f6f6ff2f84235d1be5da55020c40ff3 Mon Sep 17 00:00:00 2001
From: Anton Burnashev
Date: Wed, 10 Nov 2021 17:31:15 +0100
Subject: [PATCH 063/450] Docs: fix broken link (#8245)
---
docs/api-guide/pagination.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md
index 632af6a823..379c1975ad 100644
--- a/docs/api-guide/pagination.md
+++ b/docs/api-guide/pagination.md
@@ -312,7 +312,7 @@ The [`drf-proxy-pagination` package][drf-proxy-pagination] includes a `ProxyPagi
## link-header-pagination
-The [`django-rest-framework-link-header-pagination` package][drf-link-header-pagination] includes a `LinkHeaderPagination` class which provides pagination via an HTTP `Link` header as described in [Github's developer documentation](github-link-pagination).
+The [`django-rest-framework-link-header-pagination` package][drf-link-header-pagination] includes a `LinkHeaderPagination` class which provides pagination via an HTTP `Link` header as described in [GitHub REST API documentation][github-traversing-with-pagination].
[cite]: https://docs.djangoproject.com/en/stable/topics/pagination/
[link-header]: ../img/link-header-pagination.png
@@ -322,3 +322,4 @@ The [`django-rest-framework-link-header-pagination` package][drf-link-header-pag
[drf-link-header-pagination]: https://github.com/tbeadle/django-rest-framework-link-header-pagination
[disqus-cursor-api]: https://cra.mr/2011/03/08/building-cursors-for-the-disqus-api
[float_cursor_pagination_example]: https://gist.github.com/keturn/8bc88525a183fd41c73ffb729b8865be#file-fpcursorpagination-py
+[github-traversing-with-pagination]: https://docs.github.com/en/rest/guides/traversing-with-pagination
From 0d5250cffada2ac250e24407953d4862d04d3dae Mon Sep 17 00:00:00 2001
From: Dmytro Litvinov
Date: Mon, 15 Nov 2021 10:54:19 +0200
Subject: [PATCH 064/450] Fix link to installation of httpie (#8257)
Right now httpie moved to "httpie" organization (https://github.com/httpie/httpie) and they don't have "installation" at their GitHub. Instead of that, they have "Getting started" section with link to "Installation instructions".
---
docs/tutorial/quickstart.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md
index ee839790f1..f4dcc5606c 100644
--- a/docs/tutorial/quickstart.md
+++ b/docs/tutorial/quickstart.md
@@ -225,4 +225,4 @@ If you want to get a more in depth understanding of how REST framework fits toge
[image]: ../img/quickstart.png
[tutorial]: 1-serialization.md
[guide]: ../api-guide/requests.md
-[httpie]: https://github.com/jakubroztocil/httpie#installation
+[httpie]: https://httpie.io/docs#installation
From 580bf45ccfd5c423a938729907d813f4862dca38 Mon Sep 17 00:00:00 2001
From: Asif Saif Uddin
Date: Mon, 22 Nov 2021 16:48:58 +0600
Subject: [PATCH 065/450] test v4 beta 1 (#8222)
* test v4 beta 1
* django 4 rc1
---
tox.ini | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tox.ini b/tox.ini
index 6f49d373fc..1ab5051953 100644
--- a/tox.ini
+++ b/tox.ini
@@ -24,7 +24,7 @@ deps =
django22: Django>=2.2,<3.0
django31: Django>=3.1,<3.2
django32: Django>=3.2,<4.0
- django40: Django>=4.0a1,<5.0
+ django40: Django>=4.0rc1,<5.0
djangomain: https://github.com/django/django/archive/main.tar.gz
-rrequirements/requirements-testing.txt
-rrequirements/requirements-optionals.txt
From 380ac8e79dd85e6798eb00a730b7d4c4c4a86ebd Mon Sep 17 00:00:00 2001
From: Yecine Megdiche
Date: Mon, 6 Dec 2021 16:32:33 +0100
Subject: [PATCH 066/450] Remove old-style `super` calls (#8226)
---
docs/api-guide/filtering.md | 2 +-
docs/api-guide/serializers.md | 2 +-
docs/tutorial/4-authentication-and-permissions.md | 2 +-
rest_framework/fields.py | 2 ++
rest_framework/schemas/coreapi.py | 8 ++++----
5 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md
index 3541388ca2..512acafbd9 100644
--- a/docs/api-guide/filtering.md
+++ b/docs/api-guide/filtering.md
@@ -241,7 +241,7 @@ To dynamically change search fields based on request content, it's possible to s
def get_search_fields(self, view, request):
if request.query_params.get('title_only'):
return ['title']
- return super(CustomSearchFilter, self).get_search_fields(view, request)
+ return super().get_search_fields(view, request)
For more details, see the [Django documentation][search-django-admin].
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md
index 377f732acd..4d032bd9ec 100644
--- a/docs/api-guide/serializers.md
+++ b/docs/api-guide/serializers.md
@@ -1095,7 +1095,7 @@ For example, if you wanted to be able to set which fields should be used by a se
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
- super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md
index 79ce355c93..cb0321ea21 100644
--- a/docs/tutorial/4-authentication-and-permissions.md
+++ b/docs/tutorial/4-authentication-and-permissions.md
@@ -38,7 +38,7 @@ And now we can add a `.save()` method to our model class:
formatter = HtmlFormatter(style=self.style, linenos=linenos,
full=True, **options)
self.highlighted = highlight(self.code, lexer, formatter)
- super(Snippet, self).save(*args, **kwargs)
+ super().save(*args, **kwargs)
When that's all done we'll need to update our database tables.
Normally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index 5cafed5556..d7e7816cee 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -1491,6 +1491,8 @@ def to_internal_value(self, data):
self.fail('empty')
return {
+ # Arguments for super() are needed because of scoping inside
+ # comprehensions.
super(MultipleChoiceField, self).to_internal_value(item)
for item in data
}
diff --git a/rest_framework/schemas/coreapi.py b/rest_framework/schemas/coreapi.py
index 75ed5671af..179f0fa3c8 100644
--- a/rest_framework/schemas/coreapi.py
+++ b/rest_framework/schemas/coreapi.py
@@ -58,7 +58,7 @@ class LinkNode(OrderedDict):
def __init__(self):
self.links = []
self.methods_counter = Counter()
- super(LinkNode, self).__init__()
+ super().__init__()
def get_available_key(self, preferred_key):
if preferred_key not in self:
@@ -120,7 +120,7 @@ def __init__(self, title=None, url=None, description=None, patterns=None, urlcon
assert coreapi, '`coreapi` must be installed for schema support.'
assert coreschema, '`coreschema` must be installed for schema support.'
- super(SchemaGenerator, self).__init__(title, url, description, patterns, urlconf)
+ super().__init__(title, url, description, patterns, urlconf)
self.coerce_method_names = api_settings.SCHEMA_COERCE_METHOD_NAMES
def get_links(self, request=None):
@@ -346,7 +346,7 @@ def __init__(self, manual_fields=None):
* `manual_fields`: list of `coreapi.Field` instances that
will be added to auto-generated fields, overwriting on `Field.name`
"""
- super(AutoSchema, self).__init__()
+ super().__init__()
if manual_fields is None:
manual_fields = []
self._manual_fields = manual_fields
@@ -587,7 +587,7 @@ def __init__(self, fields, description='', encoding=None):
* `fields`: list of `coreapi.Field` instances.
* `description`: String description for view. Optional.
"""
- super(ManualSchema, self).__init__()
+ super().__init__()
assert all(isinstance(f, coreapi.Field) for f in fields), "`fields` must be a list of coreapi.Field instances"
self._fields = fields
self._description = description
From dabf2216c33a365f80354d962177d72914e8936f Mon Sep 17 00:00:00 2001
From: Jaap Roes
Date: Wed, 8 Dec 2021 15:30:34 +0100
Subject: [PATCH 067/450] Update django-cors-headers links (#8176)
---
docs/topics/ajax-csrf-cors.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/topics/ajax-csrf-cors.md b/docs/topics/ajax-csrf-cors.md
index 646f3f5638..a65e3fdf8d 100644
--- a/docs/topics/ajax-csrf-cors.md
+++ b/docs/topics/ajax-csrf-cors.md
@@ -31,11 +31,11 @@ In order to make AJAX requests, you need to include CSRF token in the HTTP heade
The best way to deal with CORS in REST framework is to add the required response headers in middleware. This ensures that CORS is supported transparently, without having to change any behavior in your views.
-[Otto Yiu][ottoyiu] maintains the [django-cors-headers] package, which is known to work correctly with REST framework APIs.
+[Adam Johnson][adamchainz] maintains the [django-cors-headers] package, which is known to work correctly with REST framework APIs.
[cite]: https://blog.codinghorror.com/preventing-csrf-and-xsrf-attacks/
[csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
[csrf-ajax]: https://docs.djangoproject.com/en/stable/ref/csrf/#ajax
[cors]: https://www.w3.org/TR/cors/
-[ottoyiu]: https://github.com/ottoyiu/
-[django-cors-headers]: https://github.com/ottoyiu/django-cors-headers/
+[adamchainz]: https://github.com/adamchainz
+[django-cors-headers]: https://github.com/adamchainz/django-cors-headers
From 37b73ef46e8cf4cc746709542d7d26f6b152a26d Mon Sep 17 00:00:00 2001
From: Jeremy Langley
Date: Wed, 8 Dec 2021 06:33:41 -0800
Subject: [PATCH 068/450] IsAdmin permissions changed to IsAdminUser (#8227)
Documentation change to keep up with the code permission changes.
Co-authored-by: Jeremy Langley
---
docs/api-guide/viewsets.md | 2 +-
docs/community/3.9-announcement.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md
index d4ab5a7317..4179725078 100644
--- a/docs/api-guide/viewsets.md
+++ b/docs/api-guide/viewsets.md
@@ -125,7 +125,7 @@ You may inspect these attributes to adjust behaviour based on the current action
if self.action == 'list':
permission_classes = [IsAuthenticated]
else:
- permission_classes = [IsAdmin]
+ permission_classes = [IsAdminUser]
return [permission() for permission in permission_classes]
## Marking extra actions for routing
diff --git a/docs/community/3.9-announcement.md b/docs/community/3.9-announcement.md
index fee6e69096..d673fdd183 100644
--- a/docs/community/3.9-announcement.md
+++ b/docs/community/3.9-announcement.md
@@ -110,7 +110,7 @@ You can now compose permission classes using the and/or operators, `&` and `|`.
For example...
```python
-permission_classes = [IsAuthenticated & (ReadOnly | IsAdmin)]
+permission_classes = [IsAuthenticated & (ReadOnly | IsAdminUser)]
```
If you're using custom permission classes then make sure that you are subclassing
From 3a762d9aac526f26ea2e9798140cb99a1d3ebc18 Mon Sep 17 00:00:00 2001
From: Matthew Pull
Date: Wed, 8 Dec 2021 14:35:06 +0000
Subject: [PATCH 069/450] Update permissions.md (#8260)
I might just be misunderstanding something (always a strong possibility!), but it seems to me that the table on the Permissions page is slightly inaccurate.
For `permission_classes`, wouldn't it have global-level permissions for list actions (rather than no permission control, as is currently listed)?
---
docs/api-guide/permissions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md
index 19bc0e66ae..5d6462b45d 100644
--- a/docs/api-guide/permissions.md
+++ b/docs/api-guide/permissions.md
@@ -286,7 +286,7 @@ The following table lists the access restriction methods and the level of contro
| | `queryset` | `permission_classes` | `serializer_class` |
|------------------------------------|------------|----------------------|--------------------|
-| Action: list | global | no | object-level* |
+| Action: list | global | global | object-level* |
| Action: create | no | global | object-level |
| Action: retrieve | global | object-level | object-level |
| Action: update | global | object-level | object-level |
From b0d407fd6344e6be9a0f1374cf53cf7e5286b67f Mon Sep 17 00:00:00 2001
From: Alexander Klimenko
Date: Wed, 8 Dec 2021 17:37:32 +0300
Subject: [PATCH 070/450] Made api_setting.UNICODE_JSON/ensure_ascii affecting
json schema (#7991)
---
rest_framework/renderers.py | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
index 5b7ba8a8c8..b0ddca2b59 100644
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -1035,13 +1035,16 @@ class CoreAPIJSONOpenAPIRenderer(_BaseOpenAPIRenderer):
media_type = 'application/vnd.oai.openapi+json'
charset = None
format = 'openapi-json'
+ ensure_ascii = not api_settings.UNICODE_JSON
def __init__(self):
assert coreapi, 'Using CoreAPIJSONOpenAPIRenderer, but `coreapi` is not installed.'
def render(self, data, media_type=None, renderer_context=None):
structure = self.get_structure(data)
- return json.dumps(structure, indent=4).encode('utf-8')
+ return json.dumps(
+ structure, indent=4,
+ ensure_ascii=self.ensure_ascii).encode('utf-8')
class OpenAPIRenderer(BaseRenderer):
@@ -1065,6 +1068,9 @@ class JSONOpenAPIRenderer(BaseRenderer):
charset = None
encoder_class = encoders.JSONEncoder
format = 'openapi-json'
+ ensure_ascii = not api_settings.UNICODE_JSON
def render(self, data, media_type=None, renderer_context=None):
- return json.dumps(data, cls=self.encoder_class, indent=2).encode('utf-8')
+ return json.dumps(
+ data, cls=self.encoder_class, indent=2,
+ ensure_ascii=self.ensure_ascii).encode('utf-8')
From 47ee3fc9a999440e721424aa5100f9eb216f0096 Mon Sep 17 00:00:00 2001
From: Chen Wen Kang <23054115+cwkang1998@users.noreply.github.com>
Date: Wed, 8 Dec 2021 22:38:42 +0800
Subject: [PATCH 071/450] Update docs related to coreapi to include deprecation
notice (#8186)
* Update docs related to coreapi to include deprecation notice
* Update docs to use reference to version 3.10 release notes instead of 3.9
---
docs/coreapi/7-schemas-and-client-libraries.md | 11 +++++++++++
docs/coreapi/from-documenting-your-api.md | 11 +++++++++++
docs/coreapi/index.md | 4 ++--
docs/coreapi/schemas.md | 8 ++++++++
4 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/docs/coreapi/7-schemas-and-client-libraries.md b/docs/coreapi/7-schemas-and-client-libraries.md
index 203d81ea5d..d95019dab6 100644
--- a/docs/coreapi/7-schemas-and-client-libraries.md
+++ b/docs/coreapi/7-schemas-and-client-libraries.md
@@ -1,5 +1,16 @@
# Tutorial 7: Schemas & client libraries
+----
+
+**DEPRECATION NOTICE:** Use of CoreAPI-based schemas were deprecated with the introduction of native OpenAPI-based schema generation as of Django REST Framework v3.10. See the [Version 3.10 Release Announcement](../community/3.10-announcement.md) for more details.
+
+If you are looking for information regarding schemas, you might want to look at these updated resources:
+
+1. [Schema](../api-guide/schemas.md)
+2. [Documenting your API](../topics/documenting-your-api.md)
+
+----
+
A schema is a machine-readable document that describes the available API
endpoints, their URLS, and what operations they support.
diff --git a/docs/coreapi/from-documenting-your-api.md b/docs/coreapi/from-documenting-your-api.md
index 604dfa6686..65ad71c7a7 100644
--- a/docs/coreapi/from-documenting-your-api.md
+++ b/docs/coreapi/from-documenting-your-api.md
@@ -1,6 +1,17 @@
## Built-in API documentation
+----
+
+**DEPRECATION NOTICE:** Use of CoreAPI-based schemas were deprecated with the introduction of native OpenAPI-based schema generation as of Django REST Framework v3.10. See the [Version 3.10 Release Announcement](../community/3.10-announcement.md) for more details.
+
+If you are looking for information regarding schemas, you might want to look at these updated resources:
+
+1. [Schema](../api-guide/schemas.md)
+2. [Documenting your API](../topics/documenting-your-api.md)
+
+----
+
The built-in API documentation includes:
* Documentation of API endpoints.
diff --git a/docs/coreapi/index.md b/docs/coreapi/index.md
index 9195eb33e4..dbcb115840 100644
--- a/docs/coreapi/index.md
+++ b/docs/coreapi/index.md
@@ -1,8 +1,8 @@
# Legacy CoreAPI Schemas Docs
-Use of CoreAPI-based schemas were deprecated with the introduction of native OpenAPI-based schema generation in Django REST Framework v3.10.
+Use of CoreAPI-based schemas were deprecated with the introduction of native OpenAPI-based schema generation as of Django REST Framework v3.10.
-See the [Version 3.10 Release Announcement](/community/3.10-announcement.md) for more details.
+See the [Version 3.10 Release Announcement](../community/3.10-announcement.md) for more details.
----
diff --git a/docs/coreapi/schemas.md b/docs/coreapi/schemas.md
index 653105a7a1..9f1482d2d8 100644
--- a/docs/coreapi/schemas.md
+++ b/docs/coreapi/schemas.md
@@ -2,6 +2,14 @@ source: schemas.py
# Schemas
+----
+
+**DEPRECATION NOTICE:** Use of CoreAPI-based schemas were deprecated with the introduction of native OpenAPI-based schema generation as of Django REST Framework v3.10. See the [Version 3.10 Release Announcement](../community/3.10-announcement.md) for more details.
+
+You are probably looking for [this page](../api-guide/schemas.md) if you want latest information regarding schemas.
+
+----
+
> A machine-readable [schema] describes what resources are available via the API, what their URLs are, how they are represented and what operations they support.
>
> — Heroku, [JSON Schema for the Heroku Platform API][cite]
From 6e0cb8a7aa2db1694b46fa3eff5a5271fd7d828e Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Wed, 8 Dec 2021 14:53:06 +0000
Subject: [PATCH 072/450] Add CryptAPI sponsorship (#8283)
---
README.md | 5 ++++-
docs/img/premium/cryptapi-readme.png | Bin 0 -> 17864 bytes
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 docs/img/premium/cryptapi-readme.png
diff --git a/README.md b/README.md
index 8ba0a5e1d3..4b089469f6 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,9 @@ The initial aim is to provide a single full-time position on REST framework.
[![][retool-img]][retool-url]
[![][bitio-img]][bitio-url]
[![][posthog-img]][posthog-url]
+[![][cryptapi-img]][cryptapi-url]
-Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry][sentry-url], [Stream][stream-url], [Rollbar][rollbar-url], [ESG][esg-url], [Retool][retool-url], [bit.io][bitio-url], and [PostHog][posthog-url].
+Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry][sentry-url], [Stream][stream-url], [Rollbar][rollbar-url], [ESG][esg-url], [Retool][retool-url], [bit.io][bitio-url], [PostHog][posthog-url], and [CryptAPI][cryptapi-url].
---
@@ -197,6 +198,7 @@ Please see the [security policy][security-policy].
[retool-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/retool-readme.png
[bitio-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/bitio-readme.png
[posthog-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/posthog-readme.png
+[posthog-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/cryptapi-readme.png
[sentry-url]: https://getsentry.com/welcome/
[stream-url]: https://getstream.io/?utm_source=drf&utm_medium=sponsorship&utm_content=developer
@@ -205,6 +207,7 @@ Please see the [security policy][security-policy].
[retool-url]: https://retool.com/?utm_source=djangorest&utm_medium=sponsorship
[bitio-url]: https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship
[posthog-url]: https://posthog.com?utm_source=drf&utm_medium=sponsorship&utm_campaign=open-source-sponsorship
+[cryptapi-url]: https://cryptapi.io
[oauth1-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-rest-framework-oauth
[oauth2-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-oauth-toolkit
diff --git a/docs/img/premium/cryptapi-readme.png b/docs/img/premium/cryptapi-readme.png
new file mode 100644
index 0000000000000000000000000000000000000000..163f6a9ea20f17909e6e38537a627f19e5766a66
GIT binary patch
literal 17864
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