Merge branch 'master' into third_party_package_for_exception_handling

This commit is contained in:
Tom Christie 2022-06-06 12:46:05 +01:00 committed by GitHub
commit 95558a1be7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 50 additions and 32 deletions

View File

@ -21,14 +21,14 @@ The initial aim is to provide a single full-time position on REST framework.
[![][sentry-img]][sentry-url] [![][sentry-img]][sentry-url]
[![][stream-img]][stream-url] [![][stream-img]][stream-url]
[![][rollbar-img]][rollbar-url] [![][spacinov-img]][spacinov-url]
[![][esg-img]][esg-url]
[![][retool-img]][retool-url] [![][retool-img]][retool-url]
[![][bitio-img]][bitio-url] [![][bitio-img]][bitio-url]
[![][posthog-img]][posthog-url] [![][posthog-img]][posthog-url]
[![][cryptapi-img]][cryptapi-url] [![][cryptapi-img]][cryptapi-url]
[![][fezto-img]][fezto-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]. Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry][sentry-url], [Stream][stream-url], [Spacinov][spacinov-url], [Retool][retool-url], [bit.io][bitio-url], [PostHog][posthog-url], [CryptAPI][cryptapi-url], and [FEZTO][fezto-url].
--- ---
@ -55,7 +55,7 @@ There is a live example API for testing purposes, [available here][sandbox].
# Requirements # Requirements
* Python (3.6, 3.7, 3.8, 3.9, 3.10) * Python (3.6, 3.7, 3.8, 3.9, 3.10)
* Django (2.2, 3.0, 3.1, 3.2, 4.0) * Django (2.2, 3.0, 3.1, 3.2, 4.0, 4.1)
We **highly recommend** and only officially support the latest patch release of We **highly recommend** and only officially support the latest patch release of
each Python and Django series. each Python and Django series.
@ -194,21 +194,21 @@ Please see the [security policy][security-policy].
[sentry-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/sentry-readme.png [sentry-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/sentry-readme.png
[stream-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/stream-readme.png [stream-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/stream-readme.png
[rollbar-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/rollbar-readme.png [spacinov-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/spacinov-readme.png
[esg-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/esg-readme.png
[retool-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/retool-readme.png [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 [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/posthog-readme.png
[cryptapi-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/cryptapi-readme.png [cryptapi-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/cryptapi-readme.png
[fezto-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/fezto-readme.png
[sentry-url]: https://getsentry.com/welcome/ [sentry-url]: https://getsentry.com/welcome/
[stream-url]: https://getstream.io/?utm_source=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage [stream-url]: https://getstream.io/?utm_source=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage
[rollbar-url]: https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial [spacinov-url]: https://www.spacinov.com/
[esg-url]: https://software.esg-usa.com/
[retool-url]: https://retool.com/?utm_source=djangorest&utm_medium=sponsorship [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 [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 [posthog-url]: https://posthog.com?utm_source=drf&utm_medium=sponsorship&utm_campaign=open-source-sponsorship
[cryptapi-url]: https://cryptapi.io [cryptapi-url]: https://cryptapi.io
[fezto-url]: https://www.fezto.xyz/?utm_source=DjangoRESTFramework
[oauth1-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-rest-framework-oauth [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 [oauth2-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-oauth-toolkit

View File

@ -120,6 +120,14 @@ Unauthenticated responses that are denied permission will result in an `HTTP 401
## TokenAuthentication ## TokenAuthentication
---
**Note:** The token authentication provided by Django REST framework is a fairly simple implementation.
For an implementation which allows more than one token per user, has some tighter security implementation details, and supports token expiry, please see the [Django REST Knox][django-rest-knox] third party package.
---
This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients. This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.
To use the `TokenAuthentication` scheme you'll need to [configure the authentication classes](#setting-the-authentication-scheme) to include `TokenAuthentication`, and additionally include `rest_framework.authtoken` in your `INSTALLED_APPS` setting: To use the `TokenAuthentication` scheme you'll need to [configure the authentication classes](#setting-the-authentication-scheme) to include `TokenAuthentication`, and additionally include `rest_framework.authtoken` in your `INSTALLED_APPS` setting:
@ -129,11 +137,9 @@ To use the `TokenAuthentication` scheme you'll need to [configure the authentica
'rest_framework.authtoken' 'rest_framework.authtoken'
] ]
--- Make sure to run `manage.py migrate` after changing your settings.
**Note:** Make sure to run `manage.py migrate` after changing your settings. The `rest_framework.authtoken` app provides Django database migrations. The `rest_framework.authtoken` app provides Django database migrations.
---
You'll also need to create tokens for your users. You'll also need to create tokens for your users.
@ -146,7 +152,7 @@ For clients to authenticate, the token key should be included in the `Authorizat
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
**Note:** If you want to use a different keyword in the header, such as `Bearer`, simply subclass `TokenAuthentication` and set the `keyword` class variable. *If you want to use a different keyword in the header, such as `Bearer`, simply subclass `TokenAuthentication` and set the `keyword` class variable.*
If successfully authenticated, `TokenAuthentication` provides the following credentials. If successfully authenticated, `TokenAuthentication` provides the following credentials.
@ -355,6 +361,10 @@ The following example will authenticate any incoming request as the user given b
The following third-party packages are also available. The following third-party packages are also available.
## django-rest-knox
[Django-rest-knox][django-rest-knox] library provides models and views to handle token-based authentication in a more secure and extensible way than the built-in TokenAuthentication scheme - with Single Page Applications and Mobile clients in mind. It provides per-client tokens, and views to generate them when provided some other authentication (usually basic authentication), to delete the token (providing a server enforced logout) and to delete all tokens (logs out all clients that a user is logged into).
## Django OAuth Toolkit ## Django OAuth Toolkit
The [Django OAuth Toolkit][django-oauth-toolkit] package provides OAuth 2.0 support and works with Python 3.4+. The package is maintained by [jazzband][jazzband] and uses the excellent [OAuthLib][oauthlib]. The package is well documented, and well supported and is currently our **recommended package for OAuth 2.0 support**. The [Django OAuth Toolkit][django-oauth-toolkit] package provides OAuth 2.0 support and works with Python 3.4+. The package is maintained by [jazzband][jazzband] and uses the excellent [OAuthLib][oauthlib]. The package is well documented, and well supported and is currently our **recommended package for OAuth 2.0 support**.
@ -424,10 +434,6 @@ There are currently two forks of this project.
[Drf-social-oauth2][drf-social-oauth2] is a framework that helps you authenticate with major social oauth2 vendors, such as Facebook, Google, Twitter, Orcid, etc. It generates tokens in a JWTed way with an easy setup. [Drf-social-oauth2][drf-social-oauth2] is a framework that helps you authenticate with major social oauth2 vendors, such as Facebook, Google, Twitter, Orcid, etc. It generates tokens in a JWTed way with an easy setup.
## django-rest-knox
[Django-rest-knox][django-rest-knox] library provides models and views to handle token-based authentication in a more secure and extensible way than the built-in TokenAuthentication scheme - with Single Page Applications and Mobile clients in mind. It provides per-client tokens, and views to generate them when provided some other authentication (usually basic authentication), to delete the token (providing a server enforced logout) and to delete all tokens (logs out all clients that a user is logged into).
## drfpasswordless ## drfpasswordless
[drfpasswordless][drfpasswordless] adds (Medium, Square Cash inspired) passwordless support to Django REST Framework's TokenAuthentication scheme. Users log in and sign up with a token sent to a contact point like an email address or a mobile number. [drfpasswordless][drfpasswordless] adds (Medium, Square Cash inspired) passwordless support to Django REST Framework's TokenAuthentication scheme. Users log in and sign up with a token sent to a contact point like an email address or a mobile number.

View File

@ -148,6 +148,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
* [django-elasticsearch-dsl-drf][django-elasticsearch-dsl-drf] - Integrate Elasticsearch DSL with Django REST framework. Package provides views, serializers, filter backends, pagination and other handy add-ons. * [django-elasticsearch-dsl-drf][django-elasticsearch-dsl-drf] - Integrate Elasticsearch DSL with Django REST framework. Package provides views, serializers, filter backends, pagination and other handy add-ons.
* [django-api-client][django-api-client] - DRF client that groups the Endpoint response, for use in CBVs and FBV as if you were working with Django's Native Models.. * [django-api-client][django-api-client] - DRF client that groups the Endpoint response, for use in CBVs and FBV as if you were working with Django's Native Models..
* [fast-drf] - A model based library for making API development faster and easier. * [fast-drf] - A model based library for making API development faster and easier.
* [django-requestlogs] - Providing middleware and other helpers for audit logging for REST framework.
* [drf-standardized-errors][drf-standardized-errors] - DRF exception handler to standardize error responses for all API endpoints. * [drf-standardized-errors][drf-standardized-errors] - DRF exception handler to standardize error responses for all API endpoints.
[cite]: http://www.software-ecosystems.com/Software_Ecosystems/Ecosystems.html [cite]: http://www.software-ecosystems.com/Software_Ecosystems/Ecosystems.html
@ -238,4 +239,5 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[graphwrap]: https://github.com/PaulGilmartin/graph_wrap [graphwrap]: https://github.com/PaulGilmartin/graph_wrap
[rest-framework-actions]: https://github.com/AlexisMunera98/rest-framework-actions [rest-framework-actions]: https://github.com/AlexisMunera98/rest-framework-actions
[fast-drf]: https://github.com/iashraful/fast-drf [fast-drf]: https://github.com/iashraful/fast-drf
[django-requestlogs]: https://github.com/Raekkeri/django-requestlogs
[drf-standardized-errors]: https://github.com/ghazi-git/drf-standardized-errors [drf-standardized-errors]: https://github.com/ghazi-git/drf-standardized-errors

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -68,16 +68,16 @@ continued development by **[signing up for a paid plan][funding]**.
<ul class="premium-promo promo"> <ul class="premium-promo promo">
<li><a href="https://getsentry.com/welcome/" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/sentry130.png)">Sentry</a></li> <li><a href="https://getsentry.com/welcome/" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/sentry130.png)">Sentry</a></li>
<li><a href="https://getstream.io/?utm_source=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/stream-130.png)">Stream</a></li> <li><a href="https://getstream.io/?utm_source=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/stream-130.png)">Stream</a></li>
<li><a href="https://software.esg-usa.com" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/esg-new-logo.png)">ESG</a></li> <li><a href="https://www.spacinov.com/" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/spacinov.png)">Spacinov</a></li>
<li><a href="https://rollbar.com" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/rollbar2.png)">Rollbar</a></li>
<li><a href="https://retool.com/?utm_source=djangorest&utm_medium=sponsorship" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/retool-sidebar.png)">Retool</a></li> <li><a href="https://retool.com/?utm_source=djangorest&utm_medium=sponsorship" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/retool-sidebar.png)">Retool</a></li>
<li><a href="https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/bitio_logo_gold_background.png)">bit.io</a></li> <li><a href="https://bit.io/jobs?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/bitio_logo_gold_background.png)">bit.io</a></li>
<li><a href="https://posthog.com?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/135996800-d49fe024-32d9-441a-98d9-4c7596287a67.png)">PostHog</a></li> <li><a href="https://posthog.com?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/135996800-d49fe024-32d9-441a-98d9-4c7596287a67.png)">PostHog</a></li>
<li><a href="https://cryptapi.io" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/cryptapi.png)">CryptAPI</a></li> <li><a href="https://cryptapi.io" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/cryptapi.png)">CryptAPI</a></li>
<li><a href="https://www.fezto.xyz/?utm_source=DjangoRESTFramework" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/fezto.png)">FEZTO</a></li>
</ul> </ul>
<div style="clear: both; padding-bottom: 20px;"></div> <div style="clear: both; padding-bottom: 20px;"></div>
*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=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage), [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), [PostHog](https://posthog.com?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship), and [CryptAPI](https://cryptapi.io).* *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=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage), [Spacinov](https://www.spacinov.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), [PostHog](https://posthog.com?utm_source=DRF&utm_medium=sponsor&utm_campaign=DRF_sponsorship), [CryptAPI](https://cryptapi.io), and [FEZTO](https://www.fezto.xyz/?utm_source=DjangoRESTFramework).*
--- ---
@ -86,7 +86,7 @@ continued development by **[signing up for a paid plan][funding]**.
REST framework requires the following: REST framework requires the following:
* Python (3.6, 3.7, 3.8, 3.9, 3.10) * Python (3.6, 3.7, 3.8, 3.9, 3.10)
* Django (2.2, 3.0, 3.1, 3.2, 4.0) * Django (2.2, 3.0, 3.1, 3.2, 4.0, 4.1)
We **highly recommend** and only officially support the latest patch release of We **highly recommend** and only officially support the latest patch release of
each Python and Django series. each Python and Django series.

View File

@ -1,2 +1,3 @@
# MkDocs to build our documentation. # MkDocs to build our documentation.
mkdocs>=1.1.2,<1.2 mkdocs>=1.1.2,<1.2
jinja2>=2.10,<3.1.0 # contextfilter has been renamed

View File

@ -27,7 +27,6 @@ from django.utils.duration import duration_string
from django.utils.encoding import is_protected_type, smart_str from django.utils.encoding import is_protected_type, smart_str
from django.utils.formats import localize_input, sanitize_separators from django.utils.formats import localize_input, sanitize_separators
from django.utils.ipv6 import clean_ipv6_address from django.utils.ipv6 import clean_ipv6_address
from django.utils.timezone import utc
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from pytz.exceptions import InvalidTimeError from pytz.exceptions import InvalidTimeError
@ -1190,7 +1189,7 @@ class DateTimeField(Field):
except InvalidTimeError: except InvalidTimeError:
self.fail('make_aware', timezone=field_timezone) self.fail('make_aware', timezone=field_timezone)
elif (field_timezone is None) and timezone.is_aware(value): elif (field_timezone is None) and timezone.is_aware(value):
return timezone.make_naive(value, utc) return timezone.make_naive(value, datetime.timezone.utc)
return value return value
def default_timezone(self): def default_timezone(self):

View File

@ -94,6 +94,7 @@ setup(
'Framework :: Django :: 3.1', 'Framework :: Django :: 3.1',
'Framework :: Django :: 3.2', 'Framework :: Django :: 3.2',
'Framework :: Django :: 4.0', 'Framework :: Django :: 4.0',
'Framework :: Django :: 4.1',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License', 'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent', 'Operating System :: OS Independent',

View File

@ -1,15 +1,16 @@
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta, timezone
from decimal import Decimal from decimal import Decimal
from uuid import uuid4 from uuid import uuid4
import pytest import pytest
from django.test import TestCase from django.test import TestCase
from django.utils.timezone import utc
from rest_framework.compat import coreapi from rest_framework.compat import coreapi
from rest_framework.utils.encoders import JSONEncoder from rest_framework.utils.encoders import JSONEncoder
from rest_framework.utils.serializer_helpers import ReturnList from rest_framework.utils.serializer_helpers import ReturnList
utc = timezone.utc
class MockList: class MockList:
def tolist(self): def tolist(self):

View File

@ -9,7 +9,7 @@ import pytz
from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ValidationError as DjangoValidationError
from django.http import QueryDict from django.http import QueryDict
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.utils.timezone import activate, deactivate, override, utc from django.utils.timezone import activate, deactivate, override
import rest_framework import rest_framework
from rest_framework import exceptions, serializers from rest_framework import exceptions, serializers
@ -17,6 +17,8 @@ from rest_framework.fields import (
BuiltinSignatureError, DjangoImageField, is_simple_callable BuiltinSignatureError, DjangoImageField, is_simple_callable
) )
utc = datetime.timezone.utc
# Tests for helper functions. # Tests for helper functions.
# --------------------------- # ---------------------------

View File

@ -12,6 +12,7 @@ import sys
import tempfile import tempfile
from collections import OrderedDict from collections import OrderedDict
import django
import pytest import pytest
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
@ -452,11 +453,14 @@ class TestPosgresFieldsMapping(TestCase):
model = ArrayFieldModel model = ArrayFieldModel
fields = ['array_field', 'array_field_with_blank'] fields = ['array_field', 'array_field_with_blank']
validators = ""
if django.VERSION < (4, 1):
validators = ", validators=[<django.core.validators.MaxLengthValidator object>]"
expected = dedent(""" expected = dedent("""
TestSerializer(): TestSerializer():
array_field = ListField(allow_empty=False, child=CharField(label='Array field', validators=[<django.core.validators.MaxLengthValidator object>])) array_field = ListField(allow_empty=False, child=CharField(label='Array field'%s))
array_field_with_blank = ListField(child=CharField(label='Array field with blank', validators=[<django.core.validators.MaxLengthValidator object>]), required=False) array_field_with_blank = ListField(child=CharField(label='Array field with blank'%s), required=False)
""") """ % (validators, validators))
self.assertEqual(repr(TestSerializer()), expected) self.assertEqual(repr(TestSerializer()), expected)
@pytest.mark.skipif(hasattr(models, 'JSONField'), reason='has models.JSONField') @pytest.mark.skipif(hasattr(models, 'JSONField'), reason='has models.JSONField')

View File

@ -3,7 +3,7 @@ envlist =
{py36,py37,py38,py39}-django22, {py36,py37,py38,py39}-django22,
{py36,py37,py38,py39}-django31, {py36,py37,py38,py39}-django31,
{py36,py37,py38,py39,py310}-django32, {py36,py37,py38,py39,py310}-django32,
{py38,py39,py310}-{django40,djangomain}, {py38,py39,py310}-{django40,django41,djangomain},
base,dist,docs, base,dist,docs,
[travis:env] [travis:env]
@ -12,6 +12,7 @@ DJANGO =
3.1: django31 3.1: django31
3.2: django32 3.2: django32
4.0: django40 4.0: django40
4.1: django41
main: djangomain main: djangomain
[testenv] [testenv]
@ -24,7 +25,8 @@ deps =
django22: Django>=2.2,<3.0 django22: Django>=2.2,<3.0
django31: Django>=3.1,<3.2 django31: Django>=3.1,<3.2
django32: Django>=3.2,<4.0 django32: Django>=3.2,<4.0
django40: Django>=4.0,<5.0 django40: Django>=4.0,<4.1
django41: Django>=4.1a1,<4.2
djangomain: https://github.com/django/django/archive/main.tar.gz djangomain: https://github.com/django/django/archive/main.tar.gz
-rrequirements/requirements-testing.txt -rrequirements/requirements-testing.txt
-rrequirements/requirements-optionals.txt -rrequirements/requirements-optionals.txt