Style notes using admonition in the documentation

https://python-markdown.github.io/extensions/admonition/
This commit is contained in:
Bruno Alla 2025-12-09 13:24:32 +00:00
parent 3a70eb2ff6
commit 1c1f1dee87
14 changed files with 103 additions and 151 deletions

View File

@ -34,13 +34,11 @@ If the requested view was only configured with renderers for `YAML` and `HTML`,
For more information on the `HTTP Accept` header, see [RFC 2616][accept-header]
---
**Note**: "q" values are not taken into account by REST framework when determining preference. The use of "q" values negatively impacts caching, and in the author's opinion they are an unnecessary and overcomplicated approach to content negotiation.
!!! note
"q" values are not taken into account by REST framework when determining preference. The use of "q" values negatively impacts caching, and in the author's opinion they are an unnecessary and overcomplicated approach to content negotiation.
This is a valid approach as the HTTP spec deliberately underspecifies how a server should weight server-based preferences against client-based preferences.
---
This is a valid approach as the HTTP spec deliberately underspecifies how a server should weight server-based preferences against client-based preferences.
# Custom content negotiation

View File

@ -17,15 +17,12 @@ REST framework includes a number of built-in Parser classes, that allow you to a
The set of valid parsers for a view is always defined as a list of classes. When `request.data` is accessed, REST framework will examine the `Content-Type` header on the incoming request, and determine which parser to use to parse the request content.
---
!!! note
When developing client applications always remember to make sure you're setting the `Content-Type` header when sending data in an HTTP request.
**Note**: When developing client applications always remember to make sure you're setting the `Content-Type` header when sending data in an HTTP request.
If you don't set the content type, most clients will default to using `'application/x-www-form-urlencoded'`, which may not be what you wanted.
If you don't set the content type, most clients will default to using `'application/x-www-form-urlencoded'`, which may not be what you wanted.
As an example, if you are sending `json` encoded data using jQuery with the [.ajax() method][jquery-ajax], you should make sure to include the `contentType: 'application/json'` setting.
---
As an example, if you are sending `json` encoded data using jQuery with the [.ajax() method][jquery-ajax], you should make sure to include the `contentType: 'application/json'` setting.
## Setting the parsers

View File

@ -51,18 +51,15 @@ For example:
self.check_object_permissions(self.request, obj)
return obj
---
!!! note
With the exception of `DjangoObjectPermissions`, the provided
permission classes in `rest_framework.permissions` **do not** implement the
methods necessary to check object permissions.
**Note**: With the exception of `DjangoObjectPermissions`, the provided
permission classes in `rest_framework.permissions` **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).
---
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
@ -118,7 +115,8 @@ Or, if you're using the `@api_view` decorator with function based views.
}
return Response(content)
__Note:__ when you set new permission classes via the class attribute or decorators you're telling the view to ignore the default list set in the __settings.py__ file.
!!! note
When you set new permission classes via the class attribute or decorators you're telling the view to ignore the default list set in the ``settings.py`` file.
Provided they inherit from `rest_framework.permissions.BasePermission`, permissions can be composed using standard Python bitwise operators. For example, `IsAuthenticatedOrReadOnly` could be written:
@ -131,7 +129,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 = {
@ -139,9 +137,8 @@ Provided they inherit from `rest_framework.permissions.BasePermission`, permissi
}
return Response(content)
__Note:__ it supports & (and), | (or) and ~ (not).
---
!!! note
Composition of permissions supports `&` (and), `|` (or) and `~` (not) operators.
# API Reference
@ -185,7 +182,7 @@ To use custom model permissions, override `DjangoModelPermissions` and set the `
Similar to `DjangoModelPermissions`, but also allows unauthenticated users to have read-only access to the API.
## DjangoObjectPermissions
## DjangoObjectPermissions
This permission class ties into Django's standard [object permissions framework][objectpermissions] that allows per-object permissions on models. In order to use this permission class, you'll also need to add a permission backend that supports object-level permissions, such as [django-guardian][guardian].
@ -199,11 +196,8 @@ Note that `DjangoObjectPermissions` **does not** require the `django-guardian` p
As with `DjangoModelPermissions` you can use custom model permissions by overriding `DjangoObjectPermissions` and setting the `.perms_map` property. Refer to the source code for details.
---
**Note**: If you need object level `view` permissions for `GET`, `HEAD` and `OPTIONS` requests and are using django-guardian for your object-level permissions backend, you'll want to consider using the `DjangoObjectPermissionsFilter` class provided by the [`djangorestframework-guardian` package][django-rest-framework-guardian]. It ensures that list endpoints only return results including objects for which the user has appropriate view permissions.
---
!!! note
If you need object level `view` permissions for `GET`, `HEAD` and `OPTIONS` requests and are using django-guardian for your object-level permissions backend, you'll want to consider using the `DjangoObjectPermissionsFilter` class provided by the [`djangorestframework-guardian` package][django-rest-framework-guardian]. It ensures that list endpoints only return results including objects for which the user has appropriate view permissions.
# Custom permissions
@ -221,11 +215,8 @@ If you need to test if a request is a read operation or a write operation, you s
else:
# Check permissions for write request
---
**Note**: The instance-level `has_object_permission` method will only be called if the view-level `has_permission` checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call `.check_object_permissions(request, obj)`. If you are using the generic views then this will be handled for you by default. (Function-based views will need to check object permissions explicitly, raising `PermissionDenied` on failure.)
---
!!! note
The instance-level `has_object_permission` method will only be called if the view-level `has_permission` checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call `.check_object_permissions(request, obj)`. If you are using the generic views then this will be handled for you by default. (Function-based views will need to check object permissions explicitly, raising `PermissionDenied` on failure.)
Custom permissions will raise a `PermissionDenied` exception if the test fails. To change the error message associated with the exception, implement a `message` attribute directly on your custom permission. Otherwise the `default_detail` attribute from `PermissionDenied` will be used. Similarly, to change the code identifier associated with the exception, implement a `code` attribute directly on your custom permission - otherwise the `default_code` attribute from `PermissionDenied` will be used.

View File

@ -183,15 +183,12 @@ Would serialize to a representation like this:
By default this field is read-write, although you can change this behavior using the `read_only` flag.
---
!!! note
This field is designed for objects that map to a URL that accepts a single URL keyword argument, as set using the `lookup_field` and `lookup_url_kwarg` arguments.
**Note**: This field is designed for objects that map to a URL that accepts a single URL keyword argument, as set using the `lookup_field` and `lookup_url_kwarg` arguments.
This is suitable for URLs that contain a single primary key or slug argument as part of the URL.
This is suitable for URLs that contain a single primary key or slug argument as part of the URL.
If you require more complex hyperlinked representation you'll need to customize the field, as described in the [custom hyperlinked fields](#custom-hyperlinked-fields) section, below.
---
If you require more complex hyperlinked representation you'll need to customize the field, as described in the [custom hyperlinked fields](#custom-hyperlinked-fields) section, below.
**Arguments**:

View File

@ -202,13 +202,16 @@ This renderer is suitable for CRUD-style web APIs that should also present a use
Note that views that have nested or list serializers for their input won't work well with the `AdminRenderer`, as the HTML forms are unable to properly support them.
**Note**: The `AdminRenderer` is only able to include links to detail pages when a properly configured `URL_FIELD_NAME` (`url` by default) attribute is present in the data. For `HyperlinkedModelSerializer` this will be the case, but for `ModelSerializer` or plain `Serializer` classes you'll need to make sure to include the field explicitly. For example here we use models `get_absolute_url` method:
!!! note
The `AdminRenderer` is only able to include links to detail pages when a properly configured `URL_FIELD_NAME` (`url` by default) attribute is present in the data. For `HyperlinkedModelSerializer` this will be the case, but for `ModelSerializer` or plain `Serializer` classes you'll need to make sure to include the field explicitly.
class AccountSerializer(serializers.ModelSerializer):
url = serializers.CharField(source='get_absolute_url', read_only=True)
For example here we use models `get_absolute_url` method:
class Meta:
model = Account
class AccountSerializer(serializers.ModelSerializer):
url = serializers.CharField(source='get_absolute_url', read_only=True)
class Meta:
model = Account
**.media_type**: `text/html`
@ -390,9 +393,8 @@ Exceptions raised and handled by an HTML renderer will attempt to render using o
Templates will render with a `RequestContext` which includes the `status_code` and `details` keys.
**Note**: If `DEBUG=True`, Django's standard traceback error page will be displayed instead of rendering the HTTP status code and text.
---
!!! note
If `DEBUG=True`, Django's standard traceback error page will be displayed instead of rendering the HTTP status code and text.
# Third party packages

View File

@ -40,17 +40,14 @@ The example above would generate the following URL patterns:
* URL pattern: `^accounts/$` Name: `'account-list'`
* URL pattern: `^accounts/{pk}/$` Name: `'account-detail'`
---
!!! note
The `basename` argument is used to specify the initial part of the view name pattern. In the example above, that's the `user` or `account` part.
**Note**: The `basename` argument is used to specify the initial part of the view name pattern. In the example above, that's the `user` or `account` part.
Typically you won't *need* to specify the `basename` argument, but if you have a viewset where you've defined a custom `get_queryset` method, then the viewset may not have a `.queryset` attribute set. If you try to register that viewset you'll see an error like this:
Typically you won't *need* to specify the `basename` argument, but if you have a viewset where you've defined a custom `get_queryset` method, then the viewset may not have a `.queryset` attribute set. If you try to register that viewset you'll see an error like this:
'basename' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.
'basename' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.
This means you'll need to explicitly set the `basename` argument when registering the viewset, as it could not be automatically determined from the model name.
---
This means you'll need to explicitly set the `basename` argument when registering the viewset, as it could not be automatically determined from the model name.
### Using `include` with routers
@ -91,16 +88,13 @@ Or both an application and instance namespace:
See Django's [URL namespaces docs][url-namespace-docs] and the [`include` API reference][include-api-reference] for more details.
---
**Note**: If using namespacing with hyperlinked serializers you'll also need to ensure that any `view_name` parameters
on the serializers correctly reflect the namespace. In the examples above you'd need to include a parameter such as
`view_name='app_name:user-detail'` for serializer fields hyperlinked to the user detail view.
The automatic `view_name` generation uses a pattern like `%(model_name)-detail`. Unless your models names actually clash
you may be better off **not** namespacing your Django REST Framework views when using hyperlinked serializers.
---
!!! note
If using namespacing with hyperlinked serializers you'll also need to ensure that any `view_name` parameters
on the serializers correctly reflect the namespace. In the examples above you'd need to include a parameter such as
`view_name='app_name:user-detail'` for serializer fields hyperlinked to the user detail view.
The automatic `view_name` generation uses a pattern like `%(model_name)-detail`. Unless your models names actually clash
you may be better off **not** namespacing your Django REST Framework views when using hyperlinked serializers.
### Routing for extra actions

View File

@ -238,15 +238,12 @@ operation = auto_schema.get_operation(...)
In compiling the schema, `SchemaGenerator` calls `get_components()` and
`get_operation()` for each view, allowed method, and path.
----
**Note**: The automatic introspection of components, and many operation
parameters relies on the relevant attributes and methods of
`GenericAPIView`: `get_serializer()`, `pagination_class`, `filter_backends`,
etc. For basic `APIView` subclasses, default introspection is essentially limited to
the URL kwarg path parameters for this reason.
----
!!! note
The automatic introspection of components, and many operation
parameters relies on the relevant attributes and methods of
`GenericAPIView`: `get_serializer()`, `pagination_class`, `filter_backends`,
etc. For basic `APIView` subclasses, default introspection is essentially limited to
the URL kwarg path parameters for this reason.
`AutoSchema` encapsulates the view introspection needed for schema generation.
Because of this all the schema generation logic is kept in a single place,

View File

@ -542,20 +542,16 @@ This option should be a list or tuple of field names, and is declared as follows
Model fields which have `editable=False` set, and `AutoField` fields will be set to read-only by default, and do not need to be added to the `read_only_fields` option.
---
!!! note
There is a special-case where a read-only field is part of a `unique_together` constraint at the model level. In this case the field is required by the serializer class in order to validate the constraint, but should also not be editable by the user.
**Note**: There is a special-case where a read-only field is part of a `unique_together` constraint at the model level. In this case the field is required by the serializer class in order to validate the constraint, but should also not be editable by the user.
The right way to deal with this is to specify the field explicitly on the serializer, providing both the `read_only=True` and `default=…` keyword arguments.
The right way to deal with this is to specify the field explicitly on the serializer, providing both the `read_only=True` and `default=…` keyword arguments.
One example of this is a read-only relation to the currently authenticated `User` which is `unique_together` with another identifier. In this case you would declare the user field like so:
One example of this is a read-only relation to the currently authenticated `User` which is `unique_together` with another identifier. In this case you would declare the user field like so:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
Please review the [Validators Documentation](/api-guide/validators/) for details on the [UniqueTogetherValidator](/api-guide/validators/#uniquetogethervalidator) and [CurrentUserDefault](/api-guide/validators/#currentuserdefault) classes.
---
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
Please review the [Validators Documentation](/api-guide/validators/) for details on the [UniqueTogetherValidator](/api-guide/validators/#uniquetogethervalidator) and [CurrentUserDefault](/api-guide/validators/#currentuserdefault) classes.
## Additional keyword arguments

View File

@ -90,36 +90,32 @@ For example, when forcibly authenticating using a token, you might do something
request = factory.get('/accounts/django-superstars/')
force_authenticate(request, user=user, token=user.auth_token)
---
!!! note
`force_authenticate` directly sets `request.user` to the in-memory `user` instance. If you are reusing the same `user` instance across multiple tests that update the saved `user` state, you may need to call [`refresh_from_db()`][refresh_from_db_docs] between tests.
**Note**: `force_authenticate` directly sets `request.user` to the in-memory `user` instance. If you are reusing the same `user` instance across multiple tests that update the saved `user` state, you may need to call [`refresh_from_db()`][refresh_from_db_docs] between tests.
!!! note
When using `APIRequestFactory`, the object that is returned is Django's standard `HttpRequest`, and not REST framework's `Request` object, which is only generated once the view is called.
---
**Note**: When using `APIRequestFactory`, the object that is returned is Django's standard `HttpRequest`, and not REST framework's `Request` object, which is only generated once the view is called.
This means that setting attributes directly on the request object may not always have the effect you expect. For example, setting `.token` directly will have no effect, and setting `.user` directly will only work if session authentication is being used.
# Request will only authenticate if `SessionAuthentication` is in use.
request = factory.get('/accounts/django-superstars/')
request.user = user
response = view(request)
If you want to test a request involving the REST frameworks 'Request' object, youll need to manually transform it first:
class DummyView(APIView):
...
factory = APIRequestFactory()
request = factory.get('/', {'demo': 'test'})
drf_request = DummyView().initialize_request(request)
assert drf_request.query_params == {'demo': ['test']}
request = factory.post('/', {'example': 'test'})
drf_request = DummyView().initialize_request(request)
assert drf_request.data.get('example') == 'test'
---
This means that setting attributes directly on the request object may not always have the effect you expect. For example, setting `.token` directly will have no effect, and setting `.user` directly will only work if session authentication is being used.
# Request will only authenticate if `SessionAuthentication` is in use.
request = factory.get('/accounts/django-superstars/')
request.user = user
response = view(request)
If you want to test a request involving the REST frameworks 'Request' object, youll need to manually transform it first:
class DummyView(APIView):
...
factory = APIRequestFactory()
request = factory.get('/', {'demo': 'test'})
drf_request = DummyView().initialize_request(request)
assert drf_request.query_params == {'demo': ['test']}
request = factory.post('/', {'example': 'test'})
drf_request = DummyView().initialize_request(request)
assert drf_request.data.get('example') == 'test'
## Forcing CSRF validation
@ -127,11 +123,8 @@ By default, requests created with `APIRequestFactory` will not have CSRF validat
factory = APIRequestFactory(enforce_csrf_checks=True)
---
**Note**: It's worth noting that Django's standard `RequestFactory` doesn't need to include this option, because when using regular Django the CSRF validation takes place in middleware, which is not run when testing views directly. When using REST framework, CSRF validation takes place inside the view, so the request factory needs to disable view-level CSRF checks.
---
!!! note
It's worth noting that Django's standard `RequestFactory` doesn't need to include this option, because when using regular Django the CSRF validation takes place in middleware, which is not run when testing views directly. When using REST framework, CSRF validation takes place inside the view, so the request factory needs to disable view-level CSRF checks.
# APIClient

View File

@ -101,11 +101,8 @@ The validator should be applied to *serializer classes*, like so:
)
]
---
**Note**: The `UniqueTogetherValidator` class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input.
---
!!! note
The `UniqueTogetherValidator` class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input.
## UniqueForDateValidator
@ -158,17 +155,11 @@ If you want the date field to be entirely hidden from the user, then use `Hidden
published = serializers.HiddenField(default=timezone.now)
---
!!! note
The `UniqueFor<Range>Validator` classes impose an implicit constraint that the fields they are applied to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input.
**Note**: The `UniqueFor<Range>Validator` classes impose an implicit constraint that the fields they are applied to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input.
---
---
**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).
# Advanced field defaults

View File

@ -45,11 +45,8 @@ For example:
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
---
**Note**: The full methods, attributes on, and relations between Django REST Framework's `APIView`, `GenericAPIView`, various `Mixins`, and `Viewsets` can be initially complex. In addition to the documentation here, the [Classy Django REST Framework][classy-drf] resource provides a browsable reference, with full methods and attributes, for each of Django REST Framework's class-based views.
---
!!! note
The full methods, attributes on, and relations between Django REST Framework's `APIView`, `GenericAPIView`, various `Mixins`, and `Viewsets` can be initially complex. In addition to the documentation here, the [Classy Django REST Framework][classy-drf] resource provides a browsable reference, with full methods and attributes, for each of Django REST Framework's class-based views.
## API policy attributes

View File

@ -131,7 +131,8 @@ You may inspect these attributes to adjust behavior based on the current action.
permission_classes = [IsAdminUser]
return [permission() for permission in permission_classes]
**Note**: the `action` attribute is not available in the `get_parsers`, `get_authenticators` and `get_content_negotiator` methods, as it is set _after_ they are called in the framework lifecycle. If you override one of these methods and try to access the `action` attribute in them, you will get an `AttributeError` error.
!!! note
The `action` attribute is not available in the `get_parsers`, `get_authenticators` and `get_content_negotiator` methods, as it is set _after_ they are called in the framework lifecycle. If you override one of these methods and try to access the `action` attribute in them, you will get an `AttributeError` error.
## Marking extra actions for routing

View File

@ -6,11 +6,8 @@ This tutorial will cover creating a simple pastebin code highlighting Web API.
The tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started. If you just want a quick overview, you should head over to the [quickstart] documentation instead.
---
**Note**: The code for this tutorial is available in the [encode/rest-framework-tutorial][repo] repository on GitHub. Feel free to clone the repository and see the code in action.
---
!!! note
The code for this tutorial is available in the [encode/rest-framework-tutorial][repo] repository on GitHub. Feel free to clone the repository and see the code in action.
## Setting up a new environment

View File

@ -135,7 +135,8 @@ Now that snippets are associated with the user that created them, let's update o
owner = serializers.ReadOnlyField(source="owner.username")
```
**Note**: Make sure you also add `'owner',` to the list of fields in the inner `Meta` class.
!!! note
Make sure you also add `'owner',` to the list of fields in the inner `Meta` class.
This field is doing something quite interesting. The `source` argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance. It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django's template language.