diff --git a/.travis.yml b/.travis.yml index 2520cf2bc..d77943dbf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ language: python cache: pip - -sudo: false - +dist: xenial matrix: fast_finish: true include: @@ -13,22 +11,25 @@ matrix: - { python: "3.5", env: DJANGO=1.11 } - { python: "3.5", env: DJANGO=2.0 } - { python: "3.5", env: DJANGO=2.1 } - - { python: "3.5", env: DJANGO=master } + - { python: "3.5", env: DJANGO=2.2 } - { python: "3.6", env: DJANGO=1.11 } - { python: "3.6", env: DJANGO=2.0 } - { python: "3.6", env: DJANGO=2.1 } + - { python: "3.6", env: DJANGO=2.2 } - { python: "3.6", env: DJANGO=master } - - { python: "3.7", env: DJANGO=2.0, dist: xenial, sudo: true } - - { python: "3.7", env: DJANGO=2.1, dist: xenial, sudo: true } - - { python: "3.7", env: DJANGO=master, dist: xenial, sudo: true } + - { python: "3.7", env: DJANGO=2.0 } + - { python: "3.7", env: DJANGO=2.1 } + - { python: "3.7", env: DJANGO=2.2 } + - { python: "3.7", env: DJANGO=master } - { python: "3.6", env: TOXENV=base } - { python: "3.6", env: TOXENV=lint } - { python: "3.6", env: TOXENV=docs } - - python: "3.6" + + - python: "3.7" env: TOXENV=dist script: - python setup.py bdist_wheel diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 29ba53955..c947a7b8c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ When answering questions make sure to help future contributors find their way ar Please keep the tone polite & professional. For some users a discussion on the REST framework mailing list or ticket tracker may be their first engagement with the open source community. First impressions count, so let's try to make everyone feel welcome. -Be mindful in the language you choose. As an example, in an environment that is heavily male-dominated, posts that start 'Hey guys,' can come across as unintentionally exclusive. It's just as easy, and more inclusive to use gender neutral language in those situations. +Be mindful in the language you choose. As an example, in an environment that is heavily male-dominated, posts that start 'Hey guys,' can come across as unintentionally exclusive. It's just as easy, and more inclusive to use gender neutral language in those situations. (e.g. 'Hey folks,') The [Django code of conduct][code-of-conduct] gives a fuller set of guidelines for participating in community forums. @@ -50,7 +50,7 @@ Getting involved in triaging incoming issues is a good way to start contributing To start developing on Django REST framework, clone the repo: - git clone git@github.com:encode/django-rest-framework.git + git clone https://github.com/encode/django-rest-framework Changes should broadly follow the [PEP 8][pep-8] style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 8f2391d29..566bf9543 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -3,7 +3,7 @@ - [ ] I have verified that that issue exists against the `master` branch of Django REST framework. - [ ] I have searched for similar issues in both open and closed tickets and cannot find a duplicate. - [ ] This is not a usage question. (Those should be directed to the [discussion group](https://groups.google.com/forum/#!forum/django-rest-framework) instead.) -- [ ] 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/topics/third-party-resources/#about-third-party-packages) where possible.) +- [ ] 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.) - [ ] I have reduced the issue to the simplest possible case. - [ ] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.) diff --git a/README.md b/README.md index ec83afea5..6bd03d11b 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,9 @@ The initial aim is to provide a single full-time position on REST framework. [![][load-impact-img]][load-impact-url] [![][kloudless-img]][kloudless-url] [![][auklet-img]][auklet-url] +[![][lightson-img]][lightson-url] -Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Rover][rover-url], [Sentry][sentry-url], [Stream][stream-url], [Rollbar][rollbar-url], [Cadre][cadre-url], [Load Impact][load-impact-url], [Kloudless][kloudless-url], and [Auklet][auklet-url]. +Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Rover][rover-url], [Sentry][sentry-url], [Stream][stream-url], [Rollbar][rollbar-url], [Cadre][cadre-url], [Load Impact][load-impact-url], [Kloudless][kloudless-url], [Auklet][auklet-url], and [Lights On Software][lightson-url]. --- @@ -55,7 +56,11 @@ There is a live example API for testing purposes, [available here][sandbox]. # Requirements * Python (3.4, 3.5, 3.6, 3.7) -* Django (1.11, 2.0, 2.1) +* Django (1.11, 2.0, 2.1, 2.2) + + +We **highly recommend** and only officially support the latest patch release of +each Python and Django series. # Installation @@ -198,6 +203,7 @@ Send a description of the issue via email to [rest-framework-security@googlegrou [load-impact-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/load-impact-readme.png [kloudless-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/kloudless-readme.png [auklet-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/auklet-readme.png +[lightson-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/lightson-readme.png [rover-url]: http://jobs.rover.com/ [sentry-url]: https://getsentry.com/welcome/ @@ -207,6 +213,7 @@ Send a description of the issue via email to [rest-framework-security@googlegrou [load-impact-url]: https://loadimpact.com/?utm_campaign=Sponsorship%20links&utm_source=drf&utm_medium=drf [kloudless-url]: https://hubs.ly/H0f30Lf0 [auklet-url]: https://auklet.io/ +[lightson-url]: https://lightsonsoftware.com [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/api-guide/authentication.md b/docs/api-guide/authentication.md index 139458ad4..5b8a9844f 100644 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -137,7 +137,7 @@ You'll also need to create tokens for your users. from rest_framework.authtoken.models import Token token = Token.objects.create(user=...) - print token.key + print(token.key) For clients to authenticate, the token key should be included in the `Authorization` HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example: @@ -391,10 +391,6 @@ Install the package using `pip`. For details on configuration and usage see the Django REST framework OAuth documentation for [authentication][django-rest-framework-oauth-authentication] and [permissions][django-rest-framework-oauth-permissions]. -## Digest Authentication - -HTTP digest authentication is a widely implemented scheme that was intended to replace HTTP basic authentication, and which provides a simple encrypted authentication mechanism. [Juan Riaza][juanriaza] maintains the [djangorestframework-digestauth][djangorestframework-digestauth] package which provides HTTP digest authentication support for REST framework. - ## JSON Web Token Authentication JSON Web Token is a fairly new standard which can be used for token-based authentication. Unlike the built-in TokenAuthentication scheme, JWT Authentication doesn't need to use a database to validate a token. A package for JWT authentication is [djangorestframework-simplejwt][djangorestframework-simplejwt] which provides some features as well as a pluggable token blacklist app. diff --git a/docs/api-guide/caching.md b/docs/api-guide/caching.md index ff51aed06..5342345e4 100644 --- a/docs/api-guide/caching.md +++ b/docs/api-guide/caching.md @@ -13,7 +13,7 @@ provided in Django. Django provides a [`method_decorator`][decorator] to use decorators with class based views. This can be used with -with other cache decorators such as [`cache_page`][page] and +other cache decorators such as [`cache_page`][page] and [`vary_on_cookie`][cookie]. ```python diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 8d25d6c78..74ce2251d 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -124,7 +124,14 @@ A boolean representation. When using HTML encoded form input be aware that omitting a value will always be treated as setting a field to `False`, even if it has a `default=True` option specified. This is because HTML checkbox inputs represent the unchecked state by omitting the value, so REST framework treats omission as if it is an empty checkbox input. -Note that default `BooleanField` instances will be generated with a `required=False` option (since Django `models.BooleanField` is always `blank=True`). If you want to change this behaviour explicitly declare the `BooleanField` on the serializer class. +Note that Django 2.1 removed the `blank` kwarg from `models.BooleanField`. +Prior to Django 2.1 `models.BooleanField` fields were always `blank=True`. Thus +since Django 2.1 default `serializers.BooleanField` instances will be generated +without the `required` kwarg (i.e. equivalent to `required=True`) whereas with +previous versions of Django, default `BooleanField` instances will be generated +with a `required=False` option. If you want to control this behaviour manually, +explicitly declare the `BooleanField` on the serializer class, or use the +`extra_kwargs` option to set the `required` flag. Corresponds to `django.db.models.fields.BooleanField`. diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md index 84c6d8d63..aff267818 100644 --- a/docs/api-guide/filtering.md +++ b/docs/api-guide/filtering.md @@ -127,7 +127,7 @@ Note that you can use both an overridden `.get_queryset()` and generic filtering """ model = Product serializer_class = ProductSerializer - filter_class = ProductFilter + filterset_class = ProductFilter def get_queryset(self): user = self.request.user @@ -160,13 +160,13 @@ Or add the filter backend to an individual View or ViewSet. ... filter_backends = (DjangoFilterBackend,) -If all you need is simple equality-based filtering, you can set a `filter_fields` attribute on the view, or viewset, listing the set of fields you wish to filter against. +If all you need is simple equality-based filtering, you can set a `filterset_fields` attribute on the view, or viewset, listing the set of fields you wish to filter against. class ProductList(generics.ListAPIView): queryset = Product.objects.all() serializer_class = ProductSerializer filter_backends = (DjangoFilterBackend,) - filter_fields = ('category', 'in_stock') + filterset_fields = ('category', 'in_stock') This will automatically create a `FilterSet` class for the given fields, and will allow you to make requests such as: @@ -188,7 +188,7 @@ When in use, the browsable API will include a `SearchFilter` control: The `SearchFilter` class will only be applied if the view has a `search_fields` attribute set. The `search_fields` attribute should be a list of names of text type fields on the model, such as `CharField` or `TextField`. from rest_framework import filters - + class UserListView(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer @@ -218,6 +218,13 @@ For example: By default, the search parameter is named `'search`', but this may be overridden with the `SEARCH_PARAM` setting. +To dynamically change search fields based on request content, it's possible to subclass the `SearchFilter` and override the `get_search_fields()` function. For example, the following subclass will only search on `title` if the query parameter `title_only` is in the request: + + class CustomSearchFilter(self, view, request): + if request.query_params.get('title_only'): + return ('title',) + return super(CustomSearchFilter, self).get_search_fields(view, request) + For more details, see the [Django documentation][search-django-admin]. --- @@ -298,9 +305,9 @@ A complete example using both `DjangoObjectPermissionsFilter` and `DjangoObjectP **permissions.py**: class CustomObjectPermissions(permissions.DjangoObjectPermissions): - """ - Similar to `DjangoObjectPermissions`, but adding 'view' permissions. - """ + """ + Similar to `DjangoObjectPermissions`, but adding 'view' permissions. + """ perms_map = { 'GET': ['%(app_label)s.view_%(model_name)s'], 'OPTIONS': ['%(app_label)s.view_%(model_name)s'], @@ -314,11 +321,11 @@ A complete example using both `DjangoObjectPermissionsFilter` and `DjangoObjectP **views.py**: class EventViewSet(viewsets.ModelViewSet): - """ - Viewset that only lists events if user has 'view' permissions, and only - allows operations on individual events if user has appropriate 'view', 'add', - 'change' or 'delete' permissions. - """ + """ + Viewset that only lists events if user has 'view' permissions, and only + allows operations on individual events if user has appropriate 'view', 'add', + 'change' or 'delete' permissions. + """ queryset = Event.objects.all() serializer_class = EventSerializer filter_backends = (filters.DjangoObjectPermissionsFilter,) diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md index 7ae351a7f..99612ef46 100644 --- a/docs/api-guide/pagination.md +++ b/docs/api-guide/pagination.md @@ -311,7 +311,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 desribed 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's developer documentation](github-link-pagination). [cite]: https://docs.djangoproject.com/en/stable/topics/pagination/ [link-header]: ../img/link-header-pagination.png diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md index 09ce4556f..be48ae7e5 100644 --- a/docs/api-guide/parsers.md +++ b/docs/api-guide/parsers.md @@ -102,7 +102,7 @@ If it is called without a `filename` URL keyword argument, then the client must ##### Notes: -* The `FileUploadParser` is for usage with native clients that can upload the file as a raw data request. For web-based uploads, or for native clients with multipart upload support, you should use the `MultiPartParser` parser instead. +* The `FileUploadParser` is for usage with native clients that can upload the file as a raw data request. For web-based uploads, or for native clients with multipart upload support, you should use the `MultiPartParser` instead. * Since this parser's `media_type` matches any content type, `FileUploadParser` should generally be the only parser set on an API view. * `FileUploadParser` respects Django's standard `FILE_UPLOAD_HANDLERS` setting, and the `request.upload_handlers` attribute. See the [Django documentation][upload-handlers] for more details. diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index 102c6ea98..6a1297e60 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -10,9 +10,9 @@ Together with [authentication] and [throttling], permissions determine whether a Permission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the `request.user` and `request.auth` properties to determine if the incoming request should be permitted. -Permissions are used to grant or deny access different classes of users to different parts of the API. +Permissions are used to grant or deny access for different classes of users to different parts of the API. -The simplest style of permission would be to allow access to any authenticated user, and deny access to any unauthenticated user. This corresponds the `IsAuthenticated` class in REST framework. +The simplest style of permission would be to allow access to any authenticated user, and deny access to any unauthenticated user. This corresponds to the `IsAuthenticated` class in REST framework. A slightly less strict style of permission would be to allow full access to authenticated users, but allow read-only access to unauthenticated users. This corresponds to the `IsAuthenticatedOrReadOnly` class in REST framework. @@ -48,6 +48,19 @@ For example: self.check_object_permissions(self.request, obj) return obj +--- + +**Note**: With the exception of `DjangoObjectPermissions`, the provided +permission classes in `rest_framework.permssions` **do not** implement the +methods necessary to check object permissions. + +If you wish to use the provided permission classes in order to check object +permissions, **you must** subclass them and implement the +`has_object_permission()` method described in the [_Custom +permissions_](#custom-permissions) section (below). + +--- + #### Limitations of object level permissions For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects. @@ -104,7 +117,7 @@ __Note:__ when you set new permission classes through class attribute or decorat Provided they inherit from `rest_framework.permissions.BasePermission`, permissions can be composed using standard Python bitwise operators. For example, `IsAuthenticatedOrReadOnly` could be written: - from rest_framework.permissions import BasePermission, IsAuthenticated + from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS from rest_framework.response import Response from rest_framework.views import APIView @@ -113,7 +126,7 @@ Provided they inherit from `rest_framework.permissions.BasePermission`, permissi return request.method in SAFE_METHODS class ExampleView(APIView): - permission_classes = (IsAuthenticated|ReadOnly) + permission_classes = (IsAuthenticated|ReadOnly,) def get(self, request, format=None): content = { @@ -121,7 +134,7 @@ Provided they inherit from `rest_framework.permissions.BasePermission`, permissi } return Response(content) -__Note:__ it only supports & -and- and | -or-. +__Note:__ it supports & (and), | (or) and ~ (not). --- @@ -274,7 +287,7 @@ The [Composed Permissions][composed-permissions] package provides a simple way t ## REST Condition -The [REST Condition][rest-condition] package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators. +The [REST Condition][rest-condition] package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators. ## DRY Rest Permissions @@ -284,9 +297,9 @@ The [DRY Rest Permissions][dry-rest-permissions] package provides the ability to The [Django Rest Framework Roles][django-rest-framework-roles] package makes it easier to parameterize your API over multiple types of users. -## Django Rest Framework API Key +## Django REST Framework API Key -The [Django Rest Framework API Key][django-rest-framework-api-key] package allows you to ensure that every request made to the server requires an API key header. You can generate one from the django admin interface. +The [Django REST Framework API Key][djangorestframework-api-key] package provides the ability to authorize clients based on customizable API key headers. This package is targeted at situations in which regular user-based authentication (e.g. `TokenAuthentication`) is not suitable, e.g. allowing non-human clients to safely use your API. API keys are generated and validated through cryptographic methods and can be created and revoked from the Django admin interface at anytime. ## Django Rest Framework Role Filters @@ -304,6 +317,6 @@ The [Django Rest Framework Role Filters][django-rest-framework-role-filters] pac [rest-condition]: https://github.com/caxap/rest_condition [dry-rest-permissions]: https://github.com/Helioscene/dry-rest-permissions [django-rest-framework-roles]: https://github.com/computer-lab/django-rest-framework-roles -[django-rest-framework-api-key]: https://github.com/manosim/django-rest-framework-api-key +[djangorestframework-api-key]: https://github.com/florimondmanca/djangorestframework-api-key [django-rest-framework-role-filters]: https://github.com/allisson/django-rest-framework-role-filters [django-rest-framework-guardian]: https://github.com/rpkilby/django-rest-framework-guardian diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md index 6a865b7d1..8665e80f6 100644 --- a/docs/api-guide/relations.md +++ b/docs/api-guide/relations.md @@ -2,11 +2,9 @@ source: relations.py # Serializer relations -> Bad programmers worry about the code. -> Good programmers worry about data structures and their relationships. +> Data structures, not algorithms, are central to programming. > -> — [Linus Torvalds][cite] - +> — [Rob Pike][cite] Relational fields are used to represent model relationships. They can be applied to `ForeignKey`, `ManyToManyField` and `OneToOneField` relationships, as well as to reverse relationships, and custom relationships such as `GenericForeignKey`. @@ -24,7 +22,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the >>> from myapp.serializers import AccountSerializer >>> serializer = AccountSerializer() - >>> print repr(serializer) # Or `print(repr(serializer))` in Python 3.x. + >>> print(repr(serializer)) AccountSerializer(): id = IntegerField(label='ID', read_only=True) name = CharField(allow_blank=True, max_length=100, required=False) @@ -48,12 +46,12 @@ In order to explain the various types of relational fields, we'll use a couple o unique_together = ('album', 'order') ordering = ['order'] - def __unicode__(self): + def __str__(self): return '%d: %s' % (self.order, self.title) ## StringRelatedField -`StringRelatedField` may be used to represent the target of the relationship using its `__unicode__` method. +`StringRelatedField` may be used to represent the target of the relationship using its `__str__` method. For example, the following serializer. @@ -512,7 +510,7 @@ For example, given the following model for a tag, which has a generic relationsh object_id = models.PositiveIntegerField() tagged_object = GenericForeignKey('content_type', 'object_id') - def __unicode__(self): + def __str__(self): return self.tag_name And the following two models, which may have associated tags: @@ -592,7 +590,7 @@ The [drf-nested-routers package][drf-nested-routers] provides routers and relati The [rest-framework-generic-relations][drf-nested-relations] library provides read/write serialization for generic foreign keys. -[cite]: https://lwn.net/Articles/193245/ +[cite]: http://users.ece.utexas.edu/~adnan/pike.html [reverse-relationships]: https://docs.djangoproject.com/en/stable/topics/db/queries/#following-relationships-backward [routers]: https://www.django-rest-framework.org/api-guide/routers#defaultrouter [generic-relations]: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/#id1 diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index a43f4be8a..4ec409681 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -89,7 +89,7 @@ The default JSON encoding style can be altered using the `UNICODE_JSON` and `COM **.media_type**: `application/json` -**.format**: `'.json'` +**.format**: `'json'` **.charset**: `None` @@ -127,7 +127,7 @@ See the [_HTML & Forms_ Topic Page][html-and-forms] for further examples of `Tem **.media_type**: `text/html` -**.format**: `'.html'` +**.format**: `'html'` **.charset**: `utf-8` @@ -149,7 +149,7 @@ You can use `StaticHTMLRenderer` either to return regular HTML pages using REST **.media_type**: `text/html` -**.format**: `'.html'` +**.format**: `'html'` **.charset**: `utf-8` @@ -165,7 +165,7 @@ This renderer will determine which other renderer would have been given highest **.media_type**: `text/html` -**.format**: `'.api'` +**.format**: `'api'` **.charset**: `utf-8` @@ -200,7 +200,7 @@ Note that views that have nested or list serializers for their input won't work **.media_type**: `text/html` -**.format**: `'.admin'` +**.format**: `'admin'` **.charset**: `utf-8` @@ -224,7 +224,7 @@ For more information see the [HTML & Forms][html-and-forms] documentation. **.media_type**: `text/html` -**.format**: `'.form'` +**.format**: `'form'` **.charset**: `utf-8` @@ -236,7 +236,7 @@ This renderer is used for rendering HTML multipart form data. **It is not suita **.media_type**: `multipart/form-data; boundary=BoUnDaRyStRiNg` -**.format**: `'.multipart'` +**.format**: `'multipart'` **.charset**: `utf-8` diff --git a/docs/api-guide/requests.md b/docs/api-guide/requests.md index 35b976c66..28450f082 100644 --- a/docs/api-guide/requests.md +++ b/docs/api-guide/requests.md @@ -50,7 +50,7 @@ The request exposes some properties that allow you to determine the result of th ## .accepted_renderer -The renderer instance what was selected by the content negotiation stage. +The renderer instance that was selected by the content negotiation stage. ## .accepted_media_type diff --git a/docs/api-guide/schemas.md b/docs/api-guide/schemas.md index 8a6688378..3d07ed621 100644 --- a/docs/api-guide/schemas.md +++ b/docs/api-guide/schemas.md @@ -112,8 +112,8 @@ has to be rendered into the actual bytes that are used in the response. REST framework includes a few different renderers that you can use for encoding the API schema. -* `renderers.OpenAPIRenderer` - Renders into YAML-based [OpenAPI][openapi], the most widely used API schema format. -* `renderers.JSONOpenAPIRenderer` - Renders into JSON-based [OpenAPI][openapi]. +* `renderers.OpenAPIRenderer` - Renders into YAML-based [OpenAPI][open-api], the most widely used API schema format. +* `renderers.JSONOpenAPIRenderer` - Renders into JSON-based [OpenAPI][open-api]. * `renderers.CoreJSONRenderer` - Renders into [Core JSON][corejson], a format designed for use with the `coreapi` client library. @@ -827,19 +827,11 @@ A short description of the meaning and intended usage of the input field. [drf-yasg][drf-yasg] generates [OpenAPI][open-api] documents suitable for code generation - nested schemas, named models, response bodies, enum/pattern/min/max validators, form parameters, etc. - -## DRF OpenAPI - -[DRF OpenAPI][drf-openapi] renders the schema generated by Django Rest Framework -in [OpenAPI][open-api] format. - - [cite]: https://blog.heroku.com/archives/2014/1/8/json_schema_for_heroku_platform_api [coreapi]: https://www.coreapi.org/ [corejson]: https://www.coreapi.org/specification/encoding/#core-json-encoding [drf-yasg]: https://github.com/axnsan12/drf-yasg/ [open-api]: https://openapis.org/ -[drf-openapi]: https://github.com/limdauto/drf_openapi [json-hyperschema]: https://json-schema.org/latest/json-schema-hypermedia.html [api-blueprint]: https://apiblueprint.org/ [static-files]: https://docs.djangoproject.com/en/stable/howto/static-files/ diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 19501718e..e25053936 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -152,7 +152,7 @@ When deserializing data, you always need to call `is_valid()` before attempting serializer.is_valid() # False serializer.errors - # {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']} + # {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']} Each key in the dictionary will be the field name, and the values will be lists of strings of any error messages corresponding to that field. The `non_field_errors` key may also be present, and will list any general validation errors. The name of the `non_field_errors` key may be customized using the `NON_FIELD_ERRORS_KEY` REST framework setting. @@ -208,7 +208,7 @@ To do any other validation that requires access to multiple fields, add a method def validate(self, data): """ - Check that the start is before the stop. + Check that start is before finish. """ if data['start'] > data['finish']: raise serializers.ValidationError("finish must occur after start") @@ -253,7 +253,7 @@ When passing data to a serializer instance, the unmodified data will be made ava By default, serializers must be passed values for all required fields or they will raise validation errors. You can use the `partial` argument in order to allow partial updates. # Update `comment` with partial data - serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True) + serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True) ## Dealing with nested objects @@ -293,7 +293,7 @@ When dealing with nested representations that support deserializing the data, an serializer.is_valid() # False serializer.errors - # {'user': {'email': [u'Enter a valid e-mail address.']}, 'created': [u'This field is required.']} + # {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']} Similarly, the `.validated_data` property will include nested data structures. @@ -415,7 +415,7 @@ You can provide arbitrary additional context by passing a `context` argument whe serializer = AccountSerializer(account, context={'request': request}) serializer.data - # {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'} + # {'id': 6, 'owner': 'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'} The context dictionary can be used within any serializer field logic, such as a custom `.to_representation()` method, by accessing the `self.context` attribute. @@ -1094,10 +1094,10 @@ This would then allow you to do the following: >>> model = User >>> fields = ('id', 'username', 'email') >>> - >>> print UserSerializer(user) + >>> print(UserSerializer(user)) {'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'} >>> - >>> print UserSerializer(user, fields=('id', 'email')) + >>> print(UserSerializer(user, fields=('id', 'email'))) {'id': 2, 'email': 'jon@example.com'} ## Customizing the default fields diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md index 9134bd08e..5ca01b4e7 100644 --- a/docs/api-guide/testing.md +++ b/docs/api-guide/testing.md @@ -209,7 +209,7 @@ directly. Note that the requests client requires you to pass fully qualified URLs. -## `RequestsClient` and working with the database +## RequestsClient and working with the database The `RequestsClient` class is useful if you want to write tests that solely interact with the service interface. This is a little stricter than using the standard Django test client, as it means that all interactions should be via the API. diff --git a/docs/api-guide/throttling.md b/docs/api-guide/throttling.md index de66396a8..dade47460 100644 --- a/docs/api-guide/throttling.md +++ b/docs/api-guide/throttling.md @@ -82,8 +82,10 @@ The throttle classes provided by REST framework use Django's cache backend. You If you need to use a cache other than `'default'`, you can do so by creating a custom throttle class and setting the `cache` attribute. For example: + from django.core.cache import caches + class CustomAnonRateThrottle(AnonRateThrottle): - cache = get_cache('alternate') + cache = caches['alternate'] You'll need to remember to also set your custom throttle class in the `'DEFAULT_THROTTLE_CLASSES'` settings key, or using the `throttle_classes` view attribute. diff --git a/docs/community/3.0-announcement.md b/docs/community/3.0-announcement.md index 83aec9e60..dc118d70c 100644 --- a/docs/community/3.0-announcement.md +++ b/docs/community/3.0-announcement.md @@ -389,7 +389,7 @@ You can include `expiry_date` as a field option on a `ModelSerializer` class. These fields will be mapped to `serializers.ReadOnlyField()` instances. >>> serializer = InvitationSerializer() - >>> print repr(serializer) + >>> print(repr(serializer)) InvitationSerializer(): to_email = EmailField(max_length=75) message = CharField(max_length=1000) @@ -960,6 +960,6 @@ The 3.2 release is planned to introduce an alternative admin-style interface to You can follow development on the GitHub site, where we use [milestones to indicate planning timescales](https://github.com/encode/django-rest-framework/milestones). [kickstarter]: https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3 -[sponsors]: https://www.django-rest-framework.org/topics/kickstarter-announcement/#sponsors +[sponsors]: https://www.django-rest-framework.org/community/kickstarter-announcement/#sponsors [mixins.py]: https://github.com/encode/django-rest-framework/blob/master/rest_framework/mixins.py [django-localization]: https://docs.djangoproject.com/en/stable/topics/i18n/translation/#localization-how-to-create-language-files diff --git a/docs/community/3.1-announcement.md b/docs/community/3.1-announcement.md index 0a2c40c9e..2213c379d 100644 --- a/docs/community/3.1-announcement.md +++ b/docs/community/3.1-announcement.md @@ -30,7 +30,7 @@ Note that as a result of this work a number of settings keys and generic view at Until now, there has only been a single built-in pagination style in REST framework. We now have page, limit/offset and cursor based schemes included by default. -The cursor based pagination scheme is particularly smart, and is a better approach for clients iterating through large or frequently changing result sets. The scheme supports paging against non-unique indexes, by using both cursor and limit/offset information. It also allows for both forward and reverse cursor pagination. Much credit goes to David Cramer for [this blog post](http://cramer.io/2011/03/08/building-cursors-for-the-disqus-api) on the subject. +The cursor based pagination scheme is particularly smart, and is a better approach for clients iterating through large or frequently changing result sets. The scheme supports paging against non-unique indexes, by using both cursor and limit/offset information. It also allows for both forward and reverse cursor pagination. Much credit goes to David Cramer for [this blog post](https://cra.mr/2011/03/08/building-cursors-for-the-disqus-api) on the subject. #### Pagination controls in the browsable API. @@ -114,7 +114,7 @@ Note that the structure of the error responses is still the same. We still have We include built-in translations both for standard exception cases, and for serializer validation errors. -The full list of supported languages can be found on our [Transifex project page](https://www.transifex.com/projects/p/django-rest-framework/). +The full list of supported languages can be found on our [Transifex project page](https://www.transifex.com/django-rest-framework-1/django-rest-framework/). If you only wish to support a subset of the supported languages, use Django's standard `LANGUAGES` setting: @@ -155,14 +155,14 @@ We've now moved a number of packages out of the core of REST framework, and into We're making this change in order to help distribute the maintenance workload, and keep better focus of the core essentials of the framework. -The change also means we can be more flexible with which external packages we recommend. For example, the excellently maintained [Django OAuth toolkit](https://github.com/evonove/django-oauth-toolkit) has now been promoted as our recommended option for integrating OAuth support. +The change also means we can be more flexible with which external packages we recommend. For example, the excellently maintained [Django OAuth toolkit](https://github.com/jazzband/django-oauth-toolkit) has now been promoted as our recommended option for integrating OAuth support. The following packages are now moved out of core and should be separately installed: * OAuth - [djangorestframework-oauth](https://jpadilla.github.io/django-rest-framework-oauth/) -* XML - [djangorestframework-xml](https://jpadilla.github.io/django-rest-framework-xml) -* YAML - [djangorestframework-yaml](https://jpadilla.github.io/django-rest-framework-yaml) -* JSONP - [djangorestframework-jsonp](https://jpadilla.github.io/django-rest-framework-jsonp) +* XML - [djangorestframework-xml](https://jpadilla.github.io/django-rest-framework-xml/) +* YAML - [djangorestframework-yaml](https://jpadilla.github.io/django-rest-framework-yaml/) +* JSONP - [djangorestframework-jsonp](https://jpadilla.github.io/django-rest-framework-jsonp/) It's worth reiterating that this change in policy shouldn't mean any work in your codebase other than adding a new requirement and modifying some import paths. For example to install XML rendering, you would now do: diff --git a/docs/community/3.2-announcement.md b/docs/community/3.2-announcement.md index a6db0e54b..a66ad5d29 100644 --- a/docs/community/3.2-announcement.md +++ b/docs/community/3.2-announcement.md @@ -10,7 +10,7 @@ We've also fixed a huge number of issues, and made numerous cleanups and improve Over the course of the 3.1.x series we've [resolved nearly 600 tickets](https://github.com/encode/django-rest-framework/issues?utf8=%E2%9C%93&q=closed%3A%3E2015-03-05) on our GitHub issue tracker. This means we're currently running at a rate of **closing around 100 issues or pull requests per month**. -None of this would have been possible without the support of our wonderful Kickstarter backers. If you're looking for a job in Django development we'd strongly recommend taking [a look through our sponsors](https://www.django-rest-framework.org/topics/kickstarter-announcement/#sponsors) and finding out who's hiring. +None of this would have been possible without the support of our wonderful Kickstarter backers. If you're looking for a job in Django development we'd strongly recommend taking [a look through our sponsors](https://www.django-rest-framework.org/community/kickstarter-announcement/#sponsors) and finding out who's hiring. ## AdminRenderer diff --git a/docs/community/3.4-announcement.md b/docs/community/3.4-announcement.md index 44270fd85..67192ecbb 100644 --- a/docs/community/3.4-announcement.md +++ b/docs/community/3.4-announcement.md @@ -36,13 +36,13 @@ Right now we're over 60% of the way towards achieving that. *Every single sign-up makes a significant impact.*
-*Many thanks to all our [awesome sponsors][sponsors], and in particular to our premium backers, [Rover](http://jobs.rover.com/), [Sentry](https://getsentry.com/welcome/), and [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf).* +*Many thanks to all our [awesome sponsors][sponsors], and in particular to our premium backers, [Rover](https://www.rover.com/careers/), [Sentry](https://sentry.io/welcome/), and [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf).* --- diff --git a/docs/community/3.5-announcement.md b/docs/community/3.5-announcement.md index dca371b84..cce2dd050 100644 --- a/docs/community/3.5-announcement.md +++ b/docs/community/3.5-announcement.md @@ -32,14 +32,14 @@ we strongly encourage you to invest in its continued development by **[signing up for a paid plan][funding]**. -*Many thanks to all our [sponsors][sponsors], and in particular to our premium backers, [Rover](http://jobs.rover.com/), [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), and [Machinalis](https://www.machinalis.com/#services).* +*Many thanks to all our [sponsors][sponsors], and in particular to our premium backers, [Rover](https://www.rover.com/careers/), [Sentry](https://sentry.io/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), and [Machinalis](https://www.machinalis.com/#services).* --- diff --git a/docs/community/3.6-announcement.md b/docs/community/3.6-announcement.md index 04e6a6669..c6e8dfa06 100644 --- a/docs/community/3.6-announcement.md +++ b/docs/community/3.6-announcement.md @@ -39,16 +39,16 @@ we strongly encourage you to invest in its continued development by **[signing up for a paid plan][funding]**.
{{ content|urlize_quoted_links }}