Skip to content

Commit

Permalink
Merge branch 'master' into migrate_setuppy_to_pryoject.toml
Browse files Browse the repository at this point in the history
  • Loading branch information
deronnax committed Oct 13, 2024
2 parents 2770f5e + d3dd45b commit 6f8da97
Show file tree
Hide file tree
Showing 83 changed files with 1,555 additions and 1,793 deletions.
9 changes: 8 additions & 1 deletion .github/ISSUE_TEMPLATE/1-issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ about: Please only raise an issue if you've been advised to do so after discussi

## Checklist

<!--
Note: REST framework is considered feature-complete. New functionality should be implemented outside the core REST framework. For details, please check the docs: https://www.django-rest-framework.org/community/third-party-packages/#about-third-party-packages
-->

- [ ] Raised initially as discussion #...
- [ ] This cannot be dealt with as a third party library. (We prefer new functionality to be [in the form of third party libraries](https://www.django-rest-framework.org/community/third-party-packages/#about-third-party-packages) where possible.)
- [ ] This is not a feature request suitable for implementation outside this project. Please elaborate what it is:
- [ ] compatibility fix for new Django/Python version ...
- [ ] other type of bug fix
- [ ] other type of improvement that does not touch existing code or change existing behavior (e.g. wrapper for new Django field)
- [ ] I have reduced the issue to the simplest possible case.
14 changes: 2 additions & 12 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ jobs:
strategy:
matrix:
python-version:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
- '3.13'

steps:
- uses: actions/checkout@v4
Expand All @@ -37,17 +36,8 @@ jobs:
- name: Install dependencies
run: python -m pip install --upgrade codecov tox

- name: Install tox-py
if: ${{ matrix.python-version == '3.6' }}
run: python -m pip install --upgrade tox-py

- name: Run tox targets for ${{ matrix.python-version }}
if: ${{ matrix.python-version != '3.6' }}
run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .)

- name: Run tox targets for ${{ matrix.python-version }}
if: ${{ matrix.python-version == '3.6' }}
run: tox --py current
run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d . | cut -f 1 -d '-')

- name: Run extra tox targets
if: ${{ matrix.python-version == '3.9' }}
Expand Down
2 changes: 1 addition & 1 deletion PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*Note*: Before submitting this pull request, please review our [contributing guidelines](https://www.django-rest-framework.org/community/contributing/#pull-requests).
*Note*: Before submitting a code change, please review our [contributing guidelines](https://www.django-rest-framework.org/community/contributing/#pull-requests).

## Description

Expand Down
15 changes: 6 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ The initial aim is to provide a single full-time position on REST framework.
[![][cryptapi-img]][cryptapi-url]
[![][fezto-img]][fezto-url]
[![][svix-img]][svix-url]
[![][zuplo-img]][zuplo-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], [FEZTO][fezto-url], and [Svix][svix-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], [FEZTO][fezto-url], [Svix][svix-url], and [Zuplo][zuplo-url].

---

Expand All @@ -45,8 +46,6 @@ Some reasons you might want to use REST framework:
* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers].
* [Extensive documentation][docs], and [great community support][group].

There is a live example API for testing purposes, [available here][sandbox].

**Below**: *Screenshot from the browsable API*

![Screenshot][image]
Expand All @@ -55,8 +54,8 @@ There is a live example API for testing purposes, [available here][sandbox].

# Requirements

* Python 3.6+
* Django 5.0, 4.2, 4.1, 4.0, 3.2, 3.1, 3.0
* Python 3.8+
* Django 4.2, 5.0, 5.1

We **highly recommend** and only officially support the latest patch release of
each Python and Django series.
Expand Down Expand Up @@ -174,8 +173,6 @@ Full documentation for the project is available at [https://www.django-rest-fram

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].

# Security

Please see the [security policy][security-policy].
Expand All @@ -186,9 +183,7 @@ Please see the [security policy][security-policy].
[codecov]: https://codecov.io/github/encode/django-rest-framework?branch=master
[pypi-version]: https://img.shields.io/pypi/v/djangorestframework.svg
[pypi]: https://pypi.org/project/djangorestframework/
[twitter]: https://twitter.com/starletdreaming
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
[sandbox]: https://restframework.herokuapp.com/

[funding]: https://fund.django-rest-framework.org/topics/funding/
[sponsors]: https://fund.django-rest-framework.org/topics/funding/#our-sponsors
Expand All @@ -202,6 +197,7 @@ Please see the [security policy][security-policy].
[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
[svix-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/svix-premium.png
[zuplo-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/zuplo-readme.png

[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
Expand All @@ -212,6 +208,7 @@ Please see the [security policy][security-policy].
[cryptapi-url]: https://cryptapi.io
[fezto-url]: https://www.fezto.xyz/?utm_source=DjangoRESTFramework
[svix-url]: https://www.svix.com/?utm_source=django-REST&utm_medium=sponsorship
[zuplo-url]: https://zuplo.link/django-gh

[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
Expand Down
7 changes: 7 additions & 0 deletions docs/api-guide/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ The kind of response that will be used depends on the authentication scheme. Al

Note that when a request may successfully authenticate, but still be denied permission to perform the request, in which case a `403 Permission Denied` response will always be used, regardless of the authentication scheme.

## Django 5.1+ `LoginRequiredMiddleware`

If you're running Django 5.1+ and use the [`LoginRequiredMiddleware`][login-required-middleware], please note that all views from DRF are opted-out of this middleware. This is because the authentication in DRF is based authentication and permissions classes, which may be determined after the middleware has been applied. Additionally, when the request is not authenticated, the middleware redirects the user to the login page, which is not suitable for API requests, where it's preferable to return a 401 status code.

REST framework offers an equivalent mechanism for DRF views via the global settings, `DEFAULT_AUTHENTICATION_CLASSES` and `DEFAULT_PERMISSION_CLASSES`. They should be changed accordingly if you need to enforce that API requests are logged in.

## Apache mod_wsgi specific configuration

Note that if deploying to [Apache using mod_wsgi][mod_wsgi_official], the authorization header is not passed through to a WSGI application by default, as it is assumed that authentication will be handled by Apache, rather than at an application level.
Expand Down Expand Up @@ -484,3 +490,4 @@ More information can be found in the [Documentation](https://django-rest-durin.r
[drfpasswordless]: https://github.com/aaronn/django-rest-framework-passwordless
[django-rest-authemail]: https://github.com/celiao/django-rest-authemail
[django-rest-durin]: https://github.com/eshaan7/django-rest-durin
[login-required-middleware]: https://docs.djangoproject.com/en/stable/ref/middleware/#django.contrib.auth.middleware.LoginRequiredMiddleware
23 changes: 23 additions & 0 deletions docs/api-guide/caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,29 @@ class PostView(APIView):
return Response(content)
```


## Using cache with @api_view decorator

When using @api_view decorator, the Django-provided method-based cache decorators such as [`cache_page`][page],
[`vary_on_cookie`][cookie] and [`vary_on_headers`][headers] can be called directly.

```python
from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_cookie

from rest_framework.decorators import api_view
from rest_framework.response import Response


@cache_page(60 * 15)
@vary_on_cookie
@api_view(["GET"])
def get_user_list(request):
content = {"user_feed": request.user.get_user_feed()}
return Response(content)
```


**NOTE:** The [`cache_page`][page] decorator only caches the
`GET` and `HEAD` responses with status 200.

Expand Down
12 changes: 2 additions & 10 deletions docs/api-guide/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,6 @@ When serializing the instance, default will be used if the object attribute or d

Note that setting a `default` value implies that the field is not required. Including both the `default` and `required` keyword arguments is invalid and will raise an error.

Notes regarding default value propagation from model to serializer:

All the default values from model will pass as default to the serializer and the options method.

If the default is callable then it will be propagated to & evaluated every time in the serializer but not in options method.

If the value for given field is not given then default value will be present in the serializer and available in serializer's methods. Specified validation on given field will be evaluated on default value as that field will be present in the serializer.

### `allow_null`

Normally an error will be raised if `None` is passed to a serializer field. Set this keyword argument to `True` if `None` should be considered a valid value.
Expand Down Expand Up @@ -299,8 +291,8 @@ Corresponds to `django.db.models.fields.DecimalField`.
* `max_digits` The maximum number of digits allowed in the number. It must be either `None` or an integer greater than or equal to `decimal_places`.
* `decimal_places` The number of decimal places to store with the number.
* `coerce_to_string` Set to `True` if string values should be returned for the representation, or `False` if `Decimal` objects should be returned. Defaults to the same value as the `COERCE_DECIMAL_TO_STRING` settings key, which will be `True` unless overridden. If `Decimal` objects are returned by the serializer, then the final output format will be determined by the renderer. Note that setting `localize` will force the value to `True`.
* `max_value` Validate that the number provided is no greater than this value.
* `min_value` Validate that the number provided is no less than this value.
* `max_value` Validate that the number provided is no greater than this value. Should be an integer or `Decimal` object.
* `min_value` Validate that the number provided is no less than this value. Should be an integer or `Decimal` object.
* `localize` Set to `True` to enable localization of input and output based on the current locale. This will also force `coerce_to_string` to `True`. Defaults to `False`. Note that data formatting is enabled if you have set `USE_L10N=True` in your settings file.
* `rounding` Sets the rounding mode used when quantizing to the configured precision. Valid values are [`decimal` module rounding modes][python-decimal-rounding-modes]. Defaults to `None`.
* `normalize_output` Will normalize the decimal value when serialized. This will strip all trailing zeroes and change the value's precision to the minimum required precision to be able to represent the value without losing data. Defaults to `False`.
Expand Down
3 changes: 1 addition & 2 deletions docs/api-guide/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,11 @@ This permission is suitable if you want to your API to allow read permissions to

This permission class ties into Django's standard `django.contrib.auth` [model permissions][contribauth]. This permission must only be applied to views that have a `.queryset` property or `get_queryset()` method. Authorization will only be granted if the user *is authenticated* and has the *relevant model permissions* assigned. The appropriate model is determined by checking `get_queryset().model` or `queryset.model`.

* `GET` requests require the user to have the `view` or `change` permission on the model
* `POST` requests require the user to have the `add` permission on the model.
* `PUT` and `PATCH` requests require the user to have the `change` permission on the model.
* `DELETE` requests require the user to have the `delete` permission on the model.

The default behaviour can also be overridden to support custom model permissions.
The default behavior can also be overridden to support custom model permissions. For example, you might want to include a `view` model permission for `GET` requests.

To use custom model permissions, override `DjangoModelPermissions` and set the `.perms_map` property. Refer to the source code for details.

Expand Down
4 changes: 2 additions & 2 deletions docs/api-guide/renderers.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ By default this will include the following keys: `view`, `request`, `response`,

The following is an example plaintext renderer that will return a response with the `data` parameter as the content of the response.

from django.utils.encoding import smart_text
from django.utils.encoding import smart_str
from rest_framework import renderers


Expand All @@ -292,7 +292,7 @@ The following is an example plaintext renderer that will return a response with
format = 'txt'

def render(self, data, accepted_media_type=None, renderer_context=None):
return smart_text(data, encoding=self.charset)
return smart_str(data, encoding=self.charset)

## Setting the character set

Expand Down
38 changes: 19 additions & 19 deletions docs/api-guide/routers.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,24 @@ The above example would now generate the following URL pattern:
* URL path: `^users/{pk}/change-password/$`
* URL name: `'user-change_password'`

### Using Django `path()` with routers

By default, the URLs created by routers use regular expressions. This behavior can be modified by setting the `use_regex_path` argument to `False` when instantiating the router, in this case [path converters][path-converters-topic-reference] are used. For example:

router = SimpleRouter(use_regex_path=False)

The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the `lookup_value_regex` attribute on the viewset or `lookup_value_converter` if using path converters. For example, you can limit the lookup to valid UUIDs:

class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'

class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_uuid'
lookup_value_converter = 'uuid'

Note that path converters will be used on all URLs registered in the router, including viewset actions.

# API Guide

## SimpleRouter
Expand All @@ -160,30 +178,13 @@ This router includes routes for the standard set of `list`, `create`, `retrieve`
<tr><td>{prefix}/{lookup}/{url_path}/</td><td>GET, or as specified by `methods` argument</td><td>`@action(detail=True)` decorated method</td><td>{basename}-{url_name}</td></tr>
</table>

By default the URLs created by `SimpleRouter` are appended with a trailing slash.
By default, the URLs created by `SimpleRouter` are appended with a trailing slash.
This behavior can be modified by setting the `trailing_slash` argument to `False` when instantiating the router. For example:

router = SimpleRouter(trailing_slash=False)

Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.

By default the URLs created by `SimpleRouter` use regular expressions. This behavior can be modified by setting the `use_regex_path` argument to `False` when instantiating the router, in this case [path converters][path-converters-topic-reference] are used. For example:

router = SimpleRouter(use_regex_path=False)

**Note**: `use_regex_path=False` only works with Django 2.x or above, since this feature was introduced in 2.0.0. See [release note][simplified-routing-release-note]


The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the `lookup_value_regex` attribute on the viewset or `lookup_value_converter` if using path converters. For example, you can limit the lookup to valid UUIDs:

class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'

class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_uuid'
lookup_value_converter = 'uuid'

## DefaultRouter

This router is similar to `SimpleRouter` as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional `.json` style format suffixes.
Expand Down Expand Up @@ -351,5 +352,4 @@ The [`DRF-extensions` package][drf-extensions] provides [routers][drf-extensions
[drf-extensions-customizable-endpoint-names]: https://chibisov.github.io/drf-extensions/docs/#controller-endpoint-name
[url-namespace-docs]: https://docs.djangoproject.com/en/4.0/topics/http/urls/#url-namespaces
[include-api-reference]: https://docs.djangoproject.com/en/4.0/ref/urls/#include
[simplified-routing-release-note]: https://docs.djangoproject.com/en/2.0/releases/2.0/#simplified-url-routing-syntax
[path-converters-topic-reference]: https://docs.djangoproject.com/en/2.0/topics/http/urls/#path-converters
2 changes: 0 additions & 2 deletions docs/api-guide/serializers.md
Original file line number Diff line number Diff line change
Expand Up @@ -845,8 +845,6 @@ Here's an example of how you might choose to implement multiple updates:
class Meta:
list_serializer_class = BookListSerializer

It is possible that a third party package may be included alongside the 3.1 release that provides some automatic support for multiple update operations, similar to the `allow_add_remove` behavior that was present in REST framework 2.

#### Customizing ListSerializer initialization

When a serializer with `many=True` is instantiated, we need to determine which arguments and keyword arguments should be passed to the `.__init__()` method for both the child `Serializer` class, and for the parent `ListSerializer` class.
Expand Down
8 changes: 0 additions & 8 deletions docs/community/3.15-announcement.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ The current minimum versions of Django still is 3.0 and Python 3.6.

`ModelSerializer` generates validators for [UniqueConstraint](https://docs.djangoproject.com/en/4.0/ref/models/constraints/#uniqueconstraint) (both UniqueValidator and UniqueTogetherValidator)

## ValidationErrors improvements

The `ValidationError` has been aligned with Django's, currently supporting the same style (signature) and nesting.

## SimpleRouter non-regex matching support

By default the URLs created by `SimpleRouter` use regular expressions. This behavior can be modified by setting the `use_regex_path` argument to `False` when instantiating the router.
Expand All @@ -47,10 +43,6 @@ Dependency on pytz has been removed and deprecation warnings have been added, Dj

Searches now may contain _quoted phrases_ with spaces, each phrase is considered as a single search term, and it will raise a validation error if any null-character is provided in search. See the [Filtering API guide](../api-guide/filtering.md) for more information.

## Default values propagation

Model fields' default values are now propagated to serializer fields, for more information see the [Serializer fields API guide](../api-guide/fields.md#default).

## Other fixes and improvements

There are a number of fixes and minor improvements in this release, ranging from documentation, internal infrastructure (typing, testing, requirements, deprecation, etc.), security and overall behaviour.
Expand Down
Loading

0 comments on commit 6f8da97

Please sign in to comment.