mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-12-15 06:04:00 +03:00
Handle more notes and add "Tip" admonition styles
This commit is contained in:
parent
1c1f1dee87
commit
43f411c3e3
|
|
@ -19,13 +19,10 @@ The `request.user` property will typically be set to an instance of the `contrib
|
|||
|
||||
The `request.auth` property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.
|
||||
|
||||
---
|
||||
!!! note
|
||||
Don't forget that **authentication by itself won't allow or disallow an incoming request**, it simply identifies the credentials that the request was made with.
|
||||
|
||||
**Note:** Don't forget that **authentication by itself won't allow or disallow an incoming request**, it simply identifies the credentials that the request was made with.
|
||||
|
||||
For information on how to set up the permission policies for your API please see the [permissions documentation][permission].
|
||||
|
||||
---
|
||||
For information on how to set up the permission policies for your API please see the [permissions documentation][permission].
|
||||
|
||||
## How authentication is determined
|
||||
|
||||
|
|
@ -122,17 +119,15 @@ Unauthenticated responses that are denied permission will result in an `HTTP 401
|
|||
|
||||
WWW-Authenticate: Basic realm="api"
|
||||
|
||||
**Note:** If you use `BasicAuthentication` in production you must ensure that your API is only available over `https`. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.
|
||||
!!! note
|
||||
If you use `BasicAuthentication` in production you must ensure that your API is only available over `https`. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.
|
||||
|
||||
## TokenAuthentication
|
||||
|
||||
---
|
||||
!!! note
|
||||
The token authentication provided by Django REST framework is a fairly simple implementation.
|
||||
|
||||
**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.
|
||||
|
||||
---
|
||||
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.
|
||||
|
||||
|
|
@ -173,11 +168,8 @@ The `curl` command line tool may be useful for testing token authenticated APIs.
|
|||
|
||||
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'
|
||||
|
||||
---
|
||||
|
||||
**Note:** If you use `TokenAuthentication` in production you must ensure that your API is only available over `https`.
|
||||
|
||||
---
|
||||
!!! note
|
||||
If you use `TokenAuthentication` in production you must ensure that your API is only available over `https`.
|
||||
|
||||
### Generating Tokens
|
||||
|
||||
|
|
@ -335,11 +327,8 @@ You *may* also override the `.authenticate_header(self, request)` method. If im
|
|||
|
||||
If the `.authenticate_header()` method is not overridden, the authentication scheme will return `HTTP 403 Forbidden` responses when an unauthenticated request is denied access.
|
||||
|
||||
---
|
||||
|
||||
**Note:** When your custom authenticator is invoked by the request object's `.user` or `.auth` properties, you may see an `AttributeError` re-raised as a `WrappedAttributeError`. This is necessary to prevent the original exception from being suppressed by the outer property access. Python will not recognize that the `AttributeError` originates from your custom authenticator and will instead assume that the request object does not have a `.user` or `.auth` property. These errors should be fixed or otherwise handled by your authenticator.
|
||||
|
||||
---
|
||||
!!! note
|
||||
When your custom authenticator is invoked by the request object's `.user` or `.auth` properties, you may see an `AttributeError` re-raised as a `WrappedAttributeError`. This is necessary to prevent the original exception from being suppressed by the outer property access. Python will not recognize that the `AttributeError` originates from your custom authenticator and will instead assume that the request object does not have a `.user` or `.auth` property. These errors should be fixed or otherwise handled by your authenticator.
|
||||
|
||||
## Example
|
||||
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ def get_user_list(request):
|
|||
```
|
||||
|
||||
|
||||
**NOTE:** The [`cache_page`][page] decorator only caches the
|
||||
`GET` and `HEAD` responses with status 200.
|
||||
!!! note
|
||||
The [`cache_page`][page] decorator only caches the `GET` and `HEAD` responses with status 200.
|
||||
|
||||
[page]: https://docs.djangoproject.com/en/stable/topics/cache/#the-per-view-cache
|
||||
[cookie]: https://docs.djangoproject.com/en/stable/topics/http/decorators/#django.views.decorators.vary.vary_on_cookie
|
||||
|
|
|
|||
|
|
@ -11,11 +11,8 @@ source:
|
|||
|
||||
Serializer fields handle converting between primitive values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.
|
||||
|
||||
---
|
||||
|
||||
**Note:** The serializer fields are declared in `fields.py`, but by convention you should import them using `from rest_framework import serializers` and refer to fields as `serializers.<FieldName>`.
|
||||
|
||||
---
|
||||
!!! note
|
||||
The serializer fields are declared in `fields.py`, but by convention you should import them using `from rest_framework import serializers` and refer to fields as `serializers.<FieldName>`.
|
||||
|
||||
## Core arguments
|
||||
|
||||
|
|
@ -565,11 +562,8 @@ The `HiddenField` class is usually only needed if you have some validation that
|
|||
|
||||
For further examples on `HiddenField` see the [validators](validators.md) documentation.
|
||||
|
||||
---
|
||||
|
||||
**Note:** `HiddenField()` does not appear in `partial=True` serializer (when making `PATCH` request).
|
||||
|
||||
---
|
||||
!!! note
|
||||
`HiddenField()` does not appear in `partial=True` serializer (when making `PATCH` request).
|
||||
|
||||
## ModelField
|
||||
|
||||
|
|
|
|||
|
|
@ -96,11 +96,8 @@ 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].
|
||||
|
||||
---
|
||||
!!! 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].
|
||||
|
||||
### Avoiding N+1 Queries
|
||||
|
||||
|
|
|
|||
|
|
@ -11,42 +11,36 @@ source:
|
|||
|
||||
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`.
|
||||
|
||||
---
|
||||
!!! note
|
||||
The relational fields are declared in `relations.py`, but by convention you should import them from the `serializers` module, using `from rest_framework import serializers` and refer to fields as `serializers.<FieldName>`.
|
||||
|
||||
**Note:** The relational fields are declared in `relations.py`, but by convention you should import them from the `serializers` module, using `from rest_framework import serializers` and refer to fields as `serializers.<FieldName>`.
|
||||
!!! 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 objects 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.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
**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 objects 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.
|
||||
|
||||
---
|
||||
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -103,15 +103,10 @@ Unlike other renderers, the data passed to the `Response` does not need to be se
|
|||
|
||||
The TemplateHTMLRenderer will create a `RequestContext`, using the `response.data` as the context dict, and determine a template name to use to render the context.
|
||||
|
||||
---
|
||||
!!! 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:
|
||||
|
||||
**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}
|
||||
```
|
||||
|
||||
---
|
||||
response.data = {'results': response.data}
|
||||
|
||||
The template name is determined by (in order of preference):
|
||||
|
||||
|
|
|
|||
|
|
@ -39,13 +39,10 @@ The `APIView` class or `@api_view` decorator will ensure that this property is a
|
|||
|
||||
You won't typically need to access this property.
|
||||
|
||||
---
|
||||
!!! note
|
||||
If a client sends malformed content, then accessing `request.data` may raise a `ParseError`. By default REST framework's `APIView` class or `@api_view` decorator will catch the error and return a `400 Bad Request` response.
|
||||
|
||||
**Note:** If a client sends malformed content, then accessing `request.data` may raise a `ParseError`. By default REST framework's `APIView` class or `@api_view` decorator will catch the error and return a `400 Bad Request` response.
|
||||
|
||||
If a client sends a request with a content-type that cannot be parsed then a `UnsupportedMediaType` exception will be raised, which by default will be caught and return a `415 Unsupported Media Type` response.
|
||||
|
||||
---
|
||||
If a client sends a request with a content-type that cannot be parsed then a `UnsupportedMediaType` exception will be raised, which by default will be caught and return a `415 Unsupported Media Type` response.
|
||||
|
||||
# Content negotiation
|
||||
|
||||
|
|
@ -91,11 +88,8 @@ The `APIView` class or `@api_view` decorator will ensure that this property is a
|
|||
|
||||
You won't typically need to access this property.
|
||||
|
||||
---
|
||||
|
||||
**Note:** You may see a `WrappedAttributeError` raised when calling the `.user` or `.auth` properties. These errors originate from an authenticator as a standard `AttributeError`, however it's necessary that they be re-raised as a different exception type in order to prevent them from being suppressed by the outer property access. Python will not recognize that the `AttributeError` originates from the authenticator and will instead assume that the request object does not have a `.user` or `.auth` property. The authenticator will need to be fixed.
|
||||
|
||||
---
|
||||
!!! note
|
||||
You may see a `WrappedAttributeError` raised when calling the `.user` or `.auth` properties. These errors originate from an authenticator as a standard `AttributeError`, however it's necessary that they be re-raised as a different exception type in order to prevent them from being suppressed by the outer property access. Python will not recognize that the `AttributeError` originates from the authenticator and will instead assume that the request object does not have a `.user` or `.auth` property. The authenticator will need to be fixed.
|
||||
|
||||
# Browser enhancements
|
||||
|
||||
|
|
|
|||
|
|
@ -192,11 +192,8 @@ Your `validate_<field_name>` methods should return the validated value or raise
|
|||
raise serializers.ValidationError("Blog post is not about Django")
|
||||
return value
|
||||
|
||||
---
|
||||
|
||||
**Note:** If your `<field_name>` is declared on your serializer with the parameter `required=False` then this validation step will not take place if the field is not included.
|
||||
|
||||
---
|
||||
!!! note
|
||||
If your `<field_name>` is declared on your serializer with the parameter `required=False` then this validation step will not take place if the field is not included.
|
||||
|
||||
#### Object-level validation
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,8 @@ If you want the date field to be entirely hidden from the user, then use `Hidden
|
|||
Validators that are applied across multiple fields in the serializer can sometimes require a field input that should not be provided by the API client, but that *is* available as input to the validator.
|
||||
For this purposes use `HiddenField`. This field will be present in `validated_data` but *will not* be used in the serializer output representation.
|
||||
|
||||
**Note:** Using a `read_only=True` field is excluded from writable fields so it won't use a `default=…` argument. Look [3.8 announcement](https://www.django-rest-framework.org/community/3.8-announcement/#altered-the-behavior-of-read_only-plus-default-on-field).
|
||||
!!! note
|
||||
Using a `read_only=True` field is excluded from writable fields so it won't use a `default=…` argument. Look [3.8 announcement](https://www.django-rest-framework.org/community/3.8-announcement/#altered-the-behavior-of-read_only-plus-default-on-field).
|
||||
|
||||
REST framework includes a couple of defaults that may be useful in this context.
|
||||
|
||||
|
|
|
|||
|
|
@ -81,32 +81,29 @@ To run the tests, clone the repository, and then:
|
|||
# Run the tests
|
||||
./runtests.py
|
||||
|
||||
---
|
||||
!!! tip
|
||||
If your tests require access to the database, do not forget to inherit from `django.test.TestCase` or use the `@pytest.mark.django_db()` decorator.
|
||||
|
||||
**Note:** if your tests require access to the database, do not forget to inherit from `django.test.TestCase` or use the `@pytest.mark.django_db()` decorator.
|
||||
|
||||
For example, with TestCase:
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
class MyDatabaseTest(TestCase):
|
||||
def test_something(self):
|
||||
# Your test code here
|
||||
pass
|
||||
|
||||
Or with decorator:
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.django_db()
|
||||
class MyDatabaseTest:
|
||||
def test_something(self):
|
||||
# Your test code here
|
||||
pass
|
||||
|
||||
You can reuse existing models defined in `tests/models.py` for your tests.
|
||||
|
||||
---
|
||||
For example, with TestCase:
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
class MyDatabaseTest(TestCase):
|
||||
def test_something(self):
|
||||
# Your test code here
|
||||
pass
|
||||
|
||||
Or with decorator:
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.django_db()
|
||||
class MyDatabaseTest:
|
||||
def test_something(self):
|
||||
# Your test code here
|
||||
pass
|
||||
|
||||
You can reuse existing models defined in `tests/models.py` for your tests.
|
||||
|
||||
### Test options
|
||||
|
||||
|
|
@ -133,7 +130,8 @@ Shorter form to run the tests for a given test method.
|
|||
./runtests.py test_this_method
|
||||
|
||||
|
||||
Note: The test case and test method matching is fuzzy and will sometimes run other tests that contain a partial string match to the given command line input.
|
||||
!!! note
|
||||
The test case and test method matching is fuzzy and will sometimes run other tests that contain a partial string match to the given command line input.
|
||||
|
||||
### Running against multiple environments
|
||||
|
||||
|
|
@ -225,13 +223,12 @@ Linking in this style means you'll be able to click the hyperlink in your Markdo
|
|||
|
||||
##### 3. Notes
|
||||
|
||||
If you want to draw attention to a note or warning, use a pair of enclosing lines, like so:
|
||||
If you want to draw attention to a note or warning, use an [admonition], like so:
|
||||
|
||||
---
|
||||
!!! note
|
||||
A useful documentation note.
|
||||
|
||||
**Note:** A useful documentation note.
|
||||
|
||||
---
|
||||
The documentation theme styles `info`, `warning`, `tip` and `danger` admonition types, but more could be added if the need arise.
|
||||
|
||||
|
||||
[cite]: https://www.w3.org/People/Berners-Lee/FAQ.html
|
||||
|
|
@ -247,3 +244,4 @@ If you want to draw attention to a note or warning, use a pair of enclosing line
|
|||
[mou]: http://mouapp.com/
|
||||
[repo]: https://github.com/encode/django-rest-framework
|
||||
[how-to-fork]: https://help.github.com/articles/fork-a-repo/
|
||||
[admonition]: https://python-markdown.github.io/extensions/admonition/
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ pip install djangorestframework
|
|||
pip install pygments # We'll be using this for the code highlighting
|
||||
```
|
||||
|
||||
**Note:** To exit the virtual environment at any time, just type `deactivate`. For more information see the [venv documentation][venv].
|
||||
!!! note
|
||||
To exit the virtual environment at any time, just type `deactivate`. For more information see the [venv documentation][venv].
|
||||
|
||||
## Getting started
|
||||
|
||||
|
|
|
|||
|
|
@ -120,25 +120,16 @@ Notice that we've also added a new `'highlight'` field. This field is of the sa
|
|||
|
||||
Because we've included format suffixed URLs such as `'.json'`, we also need to indicate on the `highlight` field that any format suffixed hyperlinks it returns should use the `'.html'` suffix.
|
||||
|
||||
---
|
||||
!!! note
|
||||
When you are manually instantiating these serializers inside your views (e.g., in `SnippetDetail` or `SnippetList`), you **must** pass `context={'request': request}` so the serializer knows how to build absolute URLs. For example, instead of:
|
||||
|
||||
**Note:**
|
||||
serializer = SnippetSerializer(snippet)
|
||||
|
||||
You must write:
|
||||
|
||||
When you are manually instantiating these serializers inside your views (e.g., in `SnippetDetail` or `SnippetList`), you **must** pass `context={'request': request}` so the serializer knows how to build absolute URLs. For example, instead of:
|
||||
|
||||
```python
|
||||
serializer = SnippetSerializer(snippet)
|
||||
```
|
||||
|
||||
You must write:
|
||||
|
||||
```python
|
||||
serializer = SnippetSerializer(snippet, context={"request": request})
|
||||
```
|
||||
|
||||
If your view is a subclass of `GenericAPIView`, you may use the `get_serializer_context()` as a convenience method.
|
||||
|
||||
---
|
||||
serializer = SnippetSerializer(snippet, context={"request": request})
|
||||
|
||||
If your view is a subclass of `GenericAPIView`, you may use the `get_serializer_context()` as a convenience method.
|
||||
|
||||
## Making sure our URL patterns are named
|
||||
|
||||
|
|
|
|||
|
|
@ -452,6 +452,12 @@ ul.sponsor {
|
|||
margin: 0 -.6rem 1em;
|
||||
padding: 0.4rem 0.6rem;
|
||||
}
|
||||
.admonition.tip {
|
||||
border: .075rem solid #1e8d21;
|
||||
}
|
||||
.admonition.tip .admonition-title {
|
||||
background: #1e8d211a;
|
||||
}
|
||||
.admonition.warning {
|
||||
border: .075rem solid #ff9844;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user