Deployed 6f7aad8f
with MkDocs version: 1.1
4
404.html
|
@ -293,6 +293,10 @@
|
|||
<a href="/community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="/community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="/community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -664,7 +668,7 @@ for user in User.objects.all():
|
|||
<p>When using <code>TokenAuthentication</code>, you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behavior. To use it, add the <code>obtain_auth_token</code> view to your URLconf:</p>
|
||||
<pre><code>from rest_framework.authtoken import views
|
||||
urlpatterns += [
|
||||
url(r'^api-token-auth/', views.obtain_auth_token)
|
||||
path('api-token-auth/', views.obtain_auth_token)
|
||||
]
|
||||
</code></pre>
|
||||
<p>Note that the URL part of the pattern can be whatever you want to use.</p>
|
||||
|
@ -696,7 +700,7 @@ class CustomAuthToken(ObtainAuthToken):
|
|||
</code></pre>
|
||||
<p>And in your <code>urls.py</code>:</p>
|
||||
<pre><code>urlpatterns += [
|
||||
url(r'^api-token-auth/', CustomAuthToken.as_view())
|
||||
path('api-token-auth/', CustomAuthToken.as_view())
|
||||
]
|
||||
</code></pre>
|
||||
<h5 id="with-django-admin"><a class="toclink" href="#with-django-admin">With Django admin</a></h5>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -1036,7 +1040,7 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
<h1 id="custom-fields"><a class="toclink" href="#custom-fields">Custom fields</a></h1>
|
||||
<p>If you want to create a custom field, you'll need to subclass <code>Field</code> and then override either one or both of the <code>.to_representation()</code> and <code>.to_internal_value()</code> methods. These two methods are used to convert between the initial datatype, and a primitive, serializable datatype. Primitive datatypes will typically be any of a number, string, boolean, <code>date</code>/<code>time</code>/<code>datetime</code> or <code>None</code>. They may also be any list or dictionary like object that only contains other primitive objects. Other types might be supported, depending on the renderer that you are using.</p>
|
||||
<p>The <code>.to_representation()</code> method is called to convert the initial datatype into a primitive, serializable datatype.</p>
|
||||
<p>The <code>to_internal_value()</code> method is called to restore a primitive datatype into its internal python representation. This method should raise a <code>serializers.ValidationError</code> if the data is invalid.</p>
|
||||
<p>The <code>.to_internal_value()</code> method is called to restore a primitive datatype into its internal python representation. This method should raise a <code>serializers.ValidationError</code> if the data is invalid.</p>
|
||||
<h2 id="examples"><a class="toclink" href="#examples">Examples</a></h2>
|
||||
<h3 id="a-basic-custom-field"><a class="toclink" href="#a-basic-custom-field">A Basic Custom Field</a></h3>
|
||||
<p>Let's look at an example of serializing a class that represents an RGB color value:</p>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -544,7 +548,7 @@ class PurchaseList(generics.ListAPIView):
|
|||
<h2 id="filtering-against-the-url"><a class="toclink" href="#filtering-against-the-url">Filtering against the URL</a></h2>
|
||||
<p>Another style of filtering might involve restricting the queryset based on some part of the URL.</p>
|
||||
<p>For example if your URL config contained an entry like this:</p>
|
||||
<pre><code>url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
|
||||
<pre><code>re_path('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
|
||||
</code></pre>
|
||||
<p>You could then write a view that returned a purchase queryset filtered by the username portion of the URL:</p>
|
||||
<pre><code>class PurchaseList(generics.ListAPIView):
|
||||
|
@ -623,9 +627,16 @@ class UserListView(generics.ListAPIView):
|
|||
<h2 id="djangofilterbackend"><a class="toclink" href="#djangofilterbackend">DjangoFilterBackend</a></h2>
|
||||
<p>The <a href="https://django-filter.readthedocs.io/en/latest/index.html"><code>django-filter</code></a> library includes a <code>DjangoFilterBackend</code> class which
|
||||
supports highly customizable field filtering for REST framework.</p>
|
||||
<p>To use <code>DjangoFilterBackend</code>, first install <code>django-filter</code>. Then add <code>django_filters</code> to Django's <code>INSTALLED_APPS</code></p>
|
||||
<p>To use <code>DjangoFilterBackend</code>, first install <code>django-filter</code>.</p>
|
||||
<pre><code>pip install django-filter
|
||||
</code></pre>
|
||||
<p>Then add <code>'django_filters'</code> to Django's <code>INSTALLED_APPS</code>:</p>
|
||||
<pre><code>INSTALLED_APPS = [
|
||||
...
|
||||
'django_filters',
|
||||
...
|
||||
]
|
||||
</code></pre>
|
||||
<p>You should now either add the filter backend to your settings:</p>
|
||||
<pre><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -460,9 +464,9 @@ used all the time.</p>
|
|||
from blog import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^/$', views.apt_root),
|
||||
url(r'^comments/$', views.comment_list),
|
||||
url(r'^comments/(?P<pk>[0-9]+)/$', views.comment_detail)
|
||||
path('', views.apt_root),
|
||||
path('comments/', views.comment_list),
|
||||
path('comments/<int:pk>/', views.comment_detail)
|
||||
]
|
||||
|
||||
urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html'])
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -575,7 +579,7 @@ class UserList(generics.ListCreateAPIView):
|
|||
return Response(serializer.data)
|
||||
</code></pre>
|
||||
<p>For very simple cases you might want to pass through any class attributes using the <code>.as_view()</code> method. For example, your URLconf might include something like the following entry:</p>
|
||||
<pre><code>url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
|
||||
<pre><code>path('users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="api-reference"><a class="toclink" href="#api-reference">API Reference</a></h1>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -590,7 +594,7 @@ class FileUploadView(views.APIView):
|
|||
# urls.py
|
||||
urlpatterns = [
|
||||
# ...
|
||||
url(r'^upload/(?P<filename>[^/]+)$', FileUploadView.as_view())
|
||||
re_path(r'^upload/(?P<filename>[^/]+)$', FileUploadView.as_view())
|
||||
]
|
||||
</code></pre>
|
||||
<hr />
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -495,6 +499,10 @@
|
|||
<a href="#django-rest-framework-role-filters">Django Rest Framework Role Filters</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#django-rest-framework-psq">Django Rest Framework PSQ</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<div class="promo">
|
||||
|
@ -690,18 +698,18 @@ class CustomerAccessPermission(permissions.BasePermission):
|
|||
...
|
||||
</code></pre>
|
||||
<h2 id="examples"><a class="toclink" href="#examples">Examples</a></h2>
|
||||
<p>The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.</p>
|
||||
<p>The following is an example of a permission class that checks the incoming request's IP address against a blocklist, and denies the request if the IP has been blocked.</p>
|
||||
<pre><code>from rest_framework import permissions
|
||||
|
||||
class BlacklistPermission(permissions.BasePermission):
|
||||
class BlocklistPermission(permissions.BasePermission):
|
||||
"""
|
||||
Global permission check for blacklisted IPs.
|
||||
Global permission check for blocked IPs.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
ip_addr = request.META['REMOTE_ADDR']
|
||||
blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
|
||||
return not blacklisted
|
||||
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
|
||||
return not blocked
|
||||
</code></pre>
|
||||
<p>As well as global permissions, that are run against all incoming requests, you can also create object-level permissions, that are only run against operations that affect a particular object instance. For example:</p>
|
||||
<pre><code>class IsOwnerOrReadOnly(permissions.BasePermission):
|
||||
|
@ -731,13 +739,15 @@ class BlacklistPermission(permissions.BasePermission):
|
|||
<h2 id="rest-condition"><a class="toclink" href="#rest-condition">REST Condition</a></h2>
|
||||
<p>The <a href="https://github.com/caxap/rest_condition">REST Condition</a> package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators.</p>
|
||||
<h2 id="dry-rest-permissions"><a class="toclink" href="#dry-rest-permissions">DRY Rest Permissions</a></h2>
|
||||
<p>The <a href="https://github.com/Helioscene/dry-rest-permissions">DRY Rest Permissions</a> package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app's data model. It also supports permission checks being returned to a client app through the API's serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrieve per user.</p>
|
||||
<p>The <a href="https://github.com/FJNR-inc/dry-rest-permissions">DRY Rest Permissions</a> package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app's data model. It also supports permission checks being returned to a client app through the API's serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrieve per user.</p>
|
||||
<h2 id="django-rest-framework-roles"><a class="toclink" href="#django-rest-framework-roles">Django Rest Framework Roles</a></h2>
|
||||
<p>The <a href="https://github.com/computer-lab/django-rest-framework-roles">Django Rest Framework Roles</a> package makes it easier to parameterize your API over multiple types of users.</p>
|
||||
<h2 id="django-rest-framework-api-key"><a class="toclink" href="#django-rest-framework-api-key">Django REST Framework API Key</a></h2>
|
||||
<p>The <a href="https://florimondmanca.github.io/djangorestframework-api-key/">Django REST Framework API Key</a> package provides permissions classes, models and helpers to add API key authorization to your API. It can be used to authorize internal or third-party backends and services (i.e. <em>machines</em>) which do not have a user account. API keys are stored securely using Django's password hashing infrastructure, and they can be viewed, edited and revoked at anytime in the Django admin.</p>
|
||||
<h2 id="django-rest-framework-role-filters"><a class="toclink" href="#django-rest-framework-role-filters">Django Rest Framework Role Filters</a></h2>
|
||||
<p>The <a href="https://github.com/allisson/django-rest-framework-role-filters">Django Rest Framework Role Filters</a> package provides simple filtering over multiple types of roles.</p>
|
||||
<h2 id="django-rest-framework-psq"><a class="toclink" href="#django-rest-framework-psq">Django Rest Framework PSQ</a></h2>
|
||||
<p>The <a href="https://github.com/drf-psq/drf-psq">Django Rest Framework PSQ</a> package is an extension that gives support for having action-based <strong>permission_classes</strong>, <strong>serializer_class</strong>, and <strong>queryset</strong> dependent on permission-based rules.</p>
|
||||
|
||||
|
||||
</div> <!--/span-->
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -575,7 +579,7 @@ class Track(models.Model):
|
|||
</code></pre>
|
||||
<h2 id="stringrelatedfield"><a class="toclink" href="#stringrelatedfield">StringRelatedField</a></h2>
|
||||
<p><code>StringRelatedField</code> may be used to represent the target of the relationship using its <code>__str__</code> method.</p>
|
||||
<p>For example, the following serializer.</p>
|
||||
<p>For example, the following serializer:</p>
|
||||
<pre><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.StringRelatedField(many=True)
|
||||
|
||||
|
@ -583,7 +587,7 @@ class Track(models.Model):
|
|||
model = Album
|
||||
fields = ['album_name', 'artist', 'tracks']
|
||||
</code></pre>
|
||||
<p>Would serialize to the following representation.</p>
|
||||
<p>Would serialize to the following representation:</p>
|
||||
<pre><code>{
|
||||
'album_name': 'Things We Lost In The Fire',
|
||||
'artist': 'Low',
|
||||
|
@ -773,7 +777,7 @@ class AlbumSerializer(serializers.ModelSerializer):
|
|||
}
|
||||
</code></pre>
|
||||
<h2 id="writable-nested-serializers"><a class="toclink" href="#writable-nested-serializers">Writable nested serializers</a></h2>
|
||||
<p>By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create <code>create()</code> and/or <code>update()</code> methods in order to explicitly specify how the child relationships should be saved.</p>
|
||||
<p>By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create <code>create()</code> and/or <code>update()</code> methods in order to explicitly specify how the child relationships should be saved:</p>
|
||||
<pre><code>class TrackSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Track
|
||||
|
@ -817,7 +821,7 @@ output representation should be generated from the model instance.</p>
|
|||
<p>If you want to implement a read-write relational field, you must also implement the <code>.to_internal_value(self, data)</code> method.</p>
|
||||
<p>To provide a dynamic queryset based on the <code>context</code>, you can also override <code>.get_queryset(self)</code> instead of specifying <code>.queryset</code> on the class or when initializing the field.</p>
|
||||
<h2 id="example_1"><a class="toclink" href="#example_1">Example</a></h2>
|
||||
<p>For example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration.</p>
|
||||
<p>For example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration:</p>
|
||||
<pre><code>import time
|
||||
|
||||
class TrackListingField(serializers.RelatedField):
|
||||
|
@ -832,7 +836,7 @@ class AlbumSerializer(serializers.ModelSerializer):
|
|||
model = Album
|
||||
fields = ['album_name', 'artist', 'tracks']
|
||||
</code></pre>
|
||||
<p>This custom field would then serialize to the following representation.</p>
|
||||
<p>This custom field would then serialize to the following representation:</p>
|
||||
<pre><code>{
|
||||
'album_name': 'Sometimes I Wish We Were an Eagle',
|
||||
'artist': 'Bill Callahan',
|
||||
|
@ -966,7 +970,7 @@ class Note(models.Model):
|
|||
text = models.CharField(max_length=1000)
|
||||
tags = GenericRelation(TaggedItem)
|
||||
</code></pre>
|
||||
<p>We could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized.</p>
|
||||
<p>We could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized:</p>
|
||||
<pre><code>class TaggedObjectRelatedField(serializers.RelatedField):
|
||||
"""
|
||||
A custom field to use for the `tagged_object` generic relationship.
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -919,7 +923,7 @@ class MyExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
|
|||
<h2 id="csv"><a class="toclink" href="#csv">CSV</a></h2>
|
||||
<p>Comma-separated values are a plain-text tabular data format, that can be easily imported into spreadsheet applications. <a href="https://github.com/mjumbewu">Mjumbe Poe</a> maintains the <a href="https://github.com/mjumbewu/django-rest-framework-csv">djangorestframework-csv</a> package which provides CSV renderer support for REST framework.</p>
|
||||
<h2 id="ultrajson"><a class="toclink" href="#ultrajson">UltraJSON</a></h2>
|
||||
<p><a href="https://github.com/esnme/ultrajson">UltraJSON</a> is an optimized C JSON encoder which can give significantly faster JSON rendering. <a href="https://github.com/hzy">Jacob Haslehurst</a> maintains the <a href="https://github.com/gizmag/drf-ujson-renderer">drf-ujson-renderer</a> package which implements JSON rendering using the UJSON package.</p>
|
||||
<p><a href="https://github.com/esnme/ultrajson">UltraJSON</a> is an optimized C JSON encoder which can give significantly faster JSON rendering. <a href="https://github.com/Amertz08">Adam Mertz</a> maintains <a href="https://github.com/Amertz08/drf_ujson2">drf_ujson2</a>, a fork of the now unmaintained <a href="https://github.com/gizmag/drf-ujson-renderer">drf-ujson-renderer</a>, which implements JSON rendering using the UJSON package.</p>
|
||||
<h2 id="camelcase-json"><a class="toclink" href="#camelcase-json">CamelCase JSON</a></h2>
|
||||
<p><a href="https://github.com/vbabiy/djangorestframework-camel-case">djangorestframework-camel-case</a> provides camel case JSON renderers and parsers for REST framework. This allows serializers to use Python-style underscored field names, but be exposed in the API as Javascript-style camel case field names. It is maintained by <a href="https://github.com/vbabiy">Vitaly Babiy</a>.</p>
|
||||
<h2 id="pandas-csv-excel-png"><a class="toclink" href="#pandas-csv-excel-png">Pandas (CSV, Excel, PNG)</a></h2>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -527,27 +531,27 @@ router.register(r'users', UserViewSet)
|
|||
router.register(r'accounts', AccountViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
|
||||
path('forgot-password/', ForgotPasswordFormView.as_view()),
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
</code></pre>
|
||||
<p>Alternatively you can use Django's <code>include</code> function, like so...</p>
|
||||
<pre><code>urlpatterns = [
|
||||
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
|
||||
url(r'^', include(router.urls)),
|
||||
path('forgot-password', ForgotPasswordFormView.as_view()),
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
</code></pre>
|
||||
<p>You may use <code>include</code> with an application namespace:</p>
|
||||
<pre><code>urlpatterns = [
|
||||
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
|
||||
url(r'^api/', include((router.urls, 'app_name'))),
|
||||
path('forgot-password/', ForgotPasswordFormView.as_view()),
|
||||
path('api/', include((router.urls, 'app_name'))),
|
||||
]
|
||||
</code></pre>
|
||||
<p>Or both an application and instance namespace:</p>
|
||||
<pre><code>urlpatterns = [
|
||||
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
|
||||
url(r'^api/', include((router.urls, 'app_name'), namespace='instance_name')),
|
||||
path('forgot-password/', ForgotPasswordFormView.as_view()),
|
||||
path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
|
||||
]
|
||||
</code></pre>
|
||||
<p>See Django's <a href="https://docs.djangoproject.com/en/1.11/topics/http/urls/#url-namespaces">URL namespaces docs</a> and the <a href="https://docs.djangoproject.com/en/2.0/ref/urls/#include"><code>include</code> API reference</a> for more details.</p>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -405,12 +409,20 @@
|
|||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#overview">Overview</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#generating-an-openapi-schema">Generating an OpenAPI Schema</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#customizing-schema-generation">Customizing Schema Generation</a>
|
||||
<a href="#schemagenerator">SchemaGenerator</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#autoschema">AutoSchema</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
@ -444,6 +456,23 @@ generating reference documentation, or driving dynamic client libraries that
|
|||
can interact with your API.</p>
|
||||
<p>Django REST Framework provides support for automatic generation of
|
||||
<a href="https://github.com/OAI/OpenAPI-Specification">OpenAPI</a> schemas.</p>
|
||||
<h2 id="overview"><a class="toclink" href="#overview">Overview</a></h2>
|
||||
<p>Schema generation has several moving parts. It's worth having an overview:</p>
|
||||
<ul>
|
||||
<li><code>SchemaGenerator</code> is a top-level class that is responsible for walking your
|
||||
configured URL patterns, finding <code>APIView</code> subclasses, enquiring for their
|
||||
schema representation, and compiling the final schema object.</li>
|
||||
<li><code>AutoSchema</code> encapsulates all the details necessary for per-view schema
|
||||
introspection. Is attached to each view via the <code>schema</code> attribute. You
|
||||
subclass <code>AutoSchema</code> in order to customize your schema.</li>
|
||||
<li>The <code>generateschema</code> management command allows you to generate a static schema
|
||||
offline.</li>
|
||||
<li>Alternatively, you can route <code>SchemaView</code> to dynamically generate and serve
|
||||
your schema.</li>
|
||||
<li><code>settings.DEFAULT_SCHEMA_CLASS</code> allows you to specify an <code>AutoSchema</code>
|
||||
subclass to serve as your project's default.</li>
|
||||
</ul>
|
||||
<p>The following sections explain more.</p>
|
||||
<h2 id="generating-an-openapi-schema"><a class="toclink" href="#generating-an-openapi-schema">Generating an OpenAPI Schema</a></h2>
|
||||
<h3 id="install-dependencies"><a class="toclink" href="#install-dependencies">Install dependencies</a></h3>
|
||||
<pre><code>pip install pyyaml uritemplate
|
||||
|
@ -513,7 +542,7 @@ urlpatterns = [
|
|||
<p><code>patterns</code>: List of url patterns to limit the schema introspection to. If you
|
||||
only want the <code>myproject.api</code> urls to be exposed in the schema:</p>
|
||||
<pre><code>schema_url_patterns = [
|
||||
url(r'^api/', include('myproject.api.urls')),
|
||||
path('api/', include('myproject.api.urls')),
|
||||
]
|
||||
|
||||
schema_view = get_schema_view(
|
||||
|
@ -536,17 +565,15 @@ schema_view = get_schema_view(
|
|||
<li><code>renderer_classes</code>: May be used to pass the set of renderer classes that can
|
||||
be used to render the API root endpoint.</li>
|
||||
</ul>
|
||||
<h2 id="customizing-schema-generation"><a class="toclink" href="#customizing-schema-generation">Customizing Schema Generation</a></h2>
|
||||
<p>You may customize schema generation at the level of the schema as a whole, or
|
||||
on a per-view basis.</p>
|
||||
<h3 id="schema-level-customization"><a class="toclink" href="#schema-level-customization">Schema Level Customization</a></h3>
|
||||
<p>In order to customize the top-level schema subclass
|
||||
<code>rest_framework.schemas.openapi.SchemaGenerator</code> and provide it as an argument
|
||||
to the <code>generateschema</code> command or <code>get_schema_view()</code> helper function.</p>
|
||||
<h4 id="schemagenerator"><a class="toclink" href="#schemagenerator">SchemaGenerator</a></h4>
|
||||
<p>A class that walks a list of routed URL patterns, requests the schema for each
|
||||
view and collates the resulting OpenAPI schema.</p>
|
||||
<p>Typically you'll instantiate <code>SchemaGenerator</code> with a <code>title</code> argument, like so:</p>
|
||||
<h2 id="schemagenerator"><a class="toclink" href="#schemagenerator">SchemaGenerator</a></h2>
|
||||
<p><strong>Schema-level customization</strong></p>
|
||||
<pre><code class="python">from rest_framework.schemas.openapi import SchemaGenerator
|
||||
</code></pre>
|
||||
|
||||
<p><code>SchemaGenerator</code> is a class that walks a list of routed URL patterns, requests
|
||||
the schema for each view and collates the resulting OpenAPI schema.</p>
|
||||
<p>Typically you won't need to instantiate <code>SchemaGenerator</code> yourself, but you can
|
||||
do so like so:</p>
|
||||
<pre><code>generator = SchemaGenerator(title='Stock Prices API')
|
||||
</code></pre>
|
||||
<p>Arguments:</p>
|
||||
|
@ -558,7 +585,11 @@ view and collates the resulting OpenAPI schema.</p>
|
|||
<li><code>patterns</code>: A list of URLs to inspect when generating the schema. Defaults to the project's URL conf.</li>
|
||||
<li><code>urlconf</code>: A URL conf module name to use when generating the schema. Defaults to <code>settings.ROOT_URLCONF</code>.</li>
|
||||
</ul>
|
||||
<h5 id="get_schemaself-request"><a class="toclink" href="#get_schemaself-request">get_schema(self, request)</a></h5>
|
||||
<p>In order to customize the top-level schema, subclass
|
||||
<code>rest_framework.schemas.openapi.SchemaGenerator</code> and provide your subclass
|
||||
as an argument to the <code>generateschema</code> command or <code>get_schema_view()</code> helper
|
||||
function.</p>
|
||||
<h3 id="get_schemaself-request"><a class="toclink" href="#get_schemaself-request">get_schema(self, request)</a></h3>
|
||||
<p>Returns a dictionary that represents the OpenAPI schema:</p>
|
||||
<pre><code>generator = SchemaGenerator(title='Stock Prices API')
|
||||
schema = generator.get_schema()
|
||||
|
@ -566,237 +597,183 @@ schema = generator.get_schema()
|
|||
<p>The <code>request</code> argument is optional, and may be used if you want to apply
|
||||
per-user permissions to the resulting schema generation.</p>
|
||||
<p>This is a good point to override if you want to customize the generated
|
||||
dictionary, for example to add custom
|
||||
<a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#specification-extensions">specification extensions</a>.</p>
|
||||
<h3 id="per-view-customization"><a class="toclink" href="#per-view-customization">Per-View Customization</a></h3>
|
||||
dictionary For example you might wish to add terms of service to the <a href="https://swagger.io/specification/#infoObject">top-level
|
||||
<code>info</code> object</a>:</p>
|
||||
<pre><code>class TOSSchemaGenerator(SchemaGenerator):
|
||||
def get_schema(self):
|
||||
schema = super().get_schema()
|
||||
schema["info"]["termsOfService"] = "https://example.com/tos.html"
|
||||
return schema
|
||||
</code></pre>
|
||||
|
||||
<h2 id="autoschema"><a class="toclink" href="#autoschema">AutoSchema</a></h2>
|
||||
<p><strong>Per-View Customization</strong></p>
|
||||
<pre><code class="python">from rest_framework.schemas.openapi import AutoSchema
|
||||
</code></pre>
|
||||
|
||||
<p>By default, view introspection is performed by an <code>AutoSchema</code> instance
|
||||
accessible via the <code>schema</code> attribute on <code>APIView</code>. This provides the
|
||||
appropriate <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#operationObject">Open API operation object</a> for the view,
|
||||
request method and path:</p>
|
||||
<pre><code>auto_schema = view.schema
|
||||
accessible via the <code>schema</code> attribute on <code>APIView</code>.</p>
|
||||
<pre><code>auto_schema = some_view.schema
|
||||
</code></pre>
|
||||
<p><code>AutoSchema</code> provides the OpenAPI elements needed for each view, request method
|
||||
and path:</p>
|
||||
<ul>
|
||||
<li>A list of <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#componentsObject">OpenAPI components</a>. In DRF terms these are
|
||||
mappings of serializers that describe request and response bodies.</li>
|
||||
<li>The appropriate <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#operationObject">OpenAPI operation object</a> that describes
|
||||
the endpoint, including path and query parameters for pagination, filtering,
|
||||
and so on.</li>
|
||||
</ul>
|
||||
<pre><code class="python">components = auto_schema.get_components(...)
|
||||
operation = auto_schema.get_operation(...)
|
||||
</code></pre>
|
||||
<p>In compiling the schema, <code>SchemaGenerator</code> calls <code>view.schema.get_operation()</code>
|
||||
for each view, allowed method, and path.</p>
|
||||
|
||||
<p>In compiling the schema, <code>SchemaGenerator</code> calls <code>get_components()</code> and
|
||||
<code>get_operation()</code> for each view, allowed method, and path.</p>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: For basic <code>APIView</code> subclasses, default introspection is essentially
|
||||
limited to the URL kwarg path parameters. For <code>GenericAPIView</code>
|
||||
subclasses, which includes all the provided class based views, <code>AutoSchema</code> will
|
||||
attempt to introspect serializer, pagination and filter fields, as well as
|
||||
provide richer path field descriptions. (The key hooks here are the relevant
|
||||
<code>GenericAPIView</code> attributes and methods: <code>get_serializer</code>, <code>pagination_class</code>,
|
||||
<code>filter_backends</code> and so on.)</p>
|
||||
<p><strong>Note</strong>: The automatic introspection of components, and many operation
|
||||
parameters relies on the relevant attributes and methods of
|
||||
<code>GenericAPIView</code>: <code>get_serializer()</code>, <code>pagination_class</code>, <code>filter_backends</code>,
|
||||
etc. For basic <code>APIView</code> subclasses, default introspection is essentially limited to
|
||||
the URL kwarg path parameters for this reason.</p>
|
||||
<hr />
|
||||
<p>In order to customize the operation generation, you should provide an <code>AutoSchema</code> subclass, overriding <code>get_operation()</code> as you need:</p>
|
||||
<pre><code> from rest_framework.views import APIView
|
||||
from rest_framework.schemas.openapi import AutoSchema
|
||||
|
||||
class CustomSchema(AutoSchema):
|
||||
def get_operation(...):
|
||||
# Implement custom introspection here (or in other sub-methods)
|
||||
|
||||
class CustomView(APIView):
|
||||
"""APIView subclass with custom schema introspection."""
|
||||
schema = CustomSchema()
|
||||
</code></pre>
|
||||
<p>This provides complete control over view introspection.</p>
|
||||
<p>You may disable schema generation for a view by setting <code>schema</code> to <code>None</code>:</p>
|
||||
<pre><code>class CustomView(APIView):
|
||||
...
|
||||
schema = None # Will not appear in schema
|
||||
</code></pre>
|
||||
<p>This also applies to extra actions for <code>ViewSet</code>s:</p>
|
||||
<pre><code>class CustomViewSet(viewsets.ModelViewSet):
|
||||
|
||||
@action(detail=True, schema=None)
|
||||
def extra_action(self, request, pk=None):
|
||||
...
|
||||
</code></pre>
|
||||
<p>If you wish to provide a base <code>AutoSchema</code> subclass to be used throughout your
|
||||
project you may adjust <code>settings.DEFAULT_SCHEMA_CLASS</code> appropriately.</p>
|
||||
<h3 id="grouping-operations-with-tags"><a class="toclink" href="#grouping-operations-with-tags">Grouping Operations With Tags</a></h3>
|
||||
<p>Tags can be used to group logical operations. Each tag name in the list MUST be unique. </p>
|
||||
<hr />
|
||||
<h4 id="django-rest-framework-generates-tags-automatically-with-the-following-logic"><a class="toclink" href="#django-rest-framework-generates-tags-automatically-with-the-following-logic">Django REST Framework generates tags automatically with the following logic:</a></h4>
|
||||
<p>Tag name will be first element from the path. Also, any <code>_</code> in path name will be replaced by a <code>-</code>.
|
||||
Consider below examples.</p>
|
||||
<p>Example 1: Consider a user management system. The following table will illustrate the tag generation logic.
|
||||
Here first element from the paths is: <code>users</code>. Hence tag wil be <code>users</code></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Http Method</th>
|
||||
<th>Path</th>
|
||||
<th>Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>PUT, PATCH, GET(Retrieve), DELETE</td>
|
||||
<td>/users/{id}/</td>
|
||||
<td>['users']</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>POST, GET(List)</td>
|
||||
<td>/users/</td>
|
||||
<td>['users']</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Example 2: Consider a restaurant management system. The System has restaurants. Each restaurant has branches.
|
||||
Consider REST APIs to deal with a branch of a particular restaurant.
|
||||
Here first element from the paths is: <code>restaurants</code>. Hence tag wil be <code>restaurants</code>.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Http Method</th>
|
||||
<th>Path</th>
|
||||
<th>Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>PUT, PATCH, GET(Retrieve), DELETE:</td>
|
||||
<td>/restaurants/{restaurant_id}/branches/{branch_id}</td>
|
||||
<td>['restaurants']</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>POST, GET(List):</td>
|
||||
<td>/restaurants/{restaurant_id}/branches/</td>
|
||||
<td>['restaurants']</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Example 3: Consider Order items for an e commerce company.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Http Method</th>
|
||||
<th>Path</th>
|
||||
<th>Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>PUT, PATCH, GET(Retrieve), DELETE</td>
|
||||
<td>/order_items/{id}/</td>
|
||||
<td>['order-items']</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>POST, GET(List)</td>
|
||||
<td>/order_items/</td>
|
||||
<td>['order-items']</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h4 id="overriding-auto-generated-tags"><a class="toclink" href="#overriding-auto-generated-tags">Overriding auto generated tags:</a></h4>
|
||||
<p>You can override auto-generated tags by passing <code>tags</code> argument to the constructor of <code>AutoSchema</code>. <code>tags</code> argument must be a list or tuple of string.</p>
|
||||
<pre><code class="python">from rest_framework.schemas.openapi import AutoSchema
|
||||
from rest_framework.views import APIView
|
||||
|
||||
class MyView(APIView):
|
||||
schema = AutoSchema(tags=['tag1', 'tag2'])
|
||||
...
|
||||
</code></pre>
|
||||
|
||||
<p>If you need more customization, you can override the <code>get_tags</code> method of <code>AutoSchema</code> class. Consider the following example:</p>
|
||||
<pre><code class="python">from rest_framework.schemas.openapi import AutoSchema
|
||||
from rest_framework.views import APIView
|
||||
|
||||
class MySchema(AutoSchema):
|
||||
...
|
||||
def get_tags(self, path, method):
|
||||
if method == 'POST':
|
||||
tags = ['tag1', 'tag2']
|
||||
elif method == 'GET':
|
||||
tags = ['tag2', 'tag3']
|
||||
elif path == '/example/path/':
|
||||
tags = ['tag3', 'tag4']
|
||||
else:
|
||||
tags = ['tag5', 'tag6', 'tag7']
|
||||
|
||||
return tags
|
||||
|
||||
class MyView(APIView):
|
||||
schema = MySchema()
|
||||
...
|
||||
</code></pre>
|
||||
|
||||
<h3 id="operationid"><a class="toclink" href="#operationid">OperationId</a></h3>
|
||||
<p>The schema generator generates an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#fixed-fields-17">operationid</a> for each operation. This <code>operationId</code> is deduced from the model name, serializer name or view name. The operationId may looks like "listItems", "retrieveItem", "updateItem", etc..
|
||||
The <code>operationId</code> is camelCase by convention.</p>
|
||||
<p>If you have several views with the same model, the generator may generate duplicate operationId.
|
||||
In order to work around this, you can override the second part of the operationId: operation name.</p>
|
||||
<pre><code class="python">from rest_framework.schemas.openapi import AutoSchema
|
||||
|
||||
class ExampleView(APIView):
|
||||
"""APIView subclass with custom schema introspection."""
|
||||
schema = AutoSchema(operation_id_base="Custom")
|
||||
</code></pre>
|
||||
|
||||
<p>The previous example will generate the following operationId: "listCustoms", "retrieveCustom", "updateCustom", "partialUpdateCustom", "destroyCustom".
|
||||
You need to provide the singular form of he operation name. For the list operation, a "s" will be appended at the end of the operation.</p>
|
||||
<p>If you need more configuration over the <code>operationId</code> field, you can override the <code>get_operation_id_base</code> and <code>get_operation_id</code> methods from the <code>AutoSchema</code> class:</p>
|
||||
<p><code>AutoSchema</code> encapsulates the view introspection needed for schema generation.
|
||||
Because of this all the schema generation logic is kept in a single place,
|
||||
rather than being spread around the already extensive view, serializer and
|
||||
field APIs.</p>
|
||||
<p>Keeping with this pattern, try not to let schema logic leak into your own
|
||||
views, serializers, or fields when customizing the schema generation. You might
|
||||
be tempted to do something like this:</p>
|
||||
<pre><code class="python">class CustomSchema(AutoSchema):
|
||||
def get_operation_id_base(self, path, method, action):
|
||||
pass
|
||||
|
||||
def get_operation_id(self, path, method):
|
||||
pass
|
||||
|
||||
class MyView(APIView):
|
||||
schema = AutoSchema(component_name="Ulysses")
|
||||
</code></pre>
|
||||
|
||||
<h3 id="components"><a class="toclink" href="#components">Components</a></h3>
|
||||
<p>Since DRF 3.12, Schema uses the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#componentsObject">OpenAPI Components</a>. This method defines components in the schema and <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#referenceObject">references them</a> inside request and response objects. By default, the component's name is deduced from the Serializer's name.</p>
|
||||
<p>Using OpenAPI's components provides the following advantages:</p>
|
||||
<ul>
|
||||
<li>The schema is more readable and lightweight.</li>
|
||||
<li>If you use the schema to generate an SDK (using <a href="https://github.com/OpenAPITools/openapi-generator">openapi-generator</a> or <a href="https://github.com/swagger-api/swagger-codegen">swagger-codegen</a>). The generator can name your SDK's models.</li>
|
||||
</ul>
|
||||
<h3 id="handling-components-schema-errors"><a class="toclink" href="#handling-components-schema-errors">Handling component's schema errors</a></h3>
|
||||
<p>You may get the following error while generating the schema:</p>
|
||||
<pre><code>"Serializer" is an invalid class name for schema generation.
|
||||
Serializer's class name should be unique and explicit. e.g. "ItemSerializer".
|
||||
</code></pre>
|
||||
|
||||
<p>This error occurs when the Serializer name is "Serializer". You should choose a component's name unique across your schema and different than "Serializer".</p>
|
||||
<p>You may also get the following warning:</p>
|
||||
<pre><code>Schema component "ComponentName" has been overriden with a different value.
|
||||
</code></pre>
|
||||
|
||||
<p>This warning occurs when different components have the same name in one schema. Your component name should be unique across your project. This is likely an error that may lead to an invalid schema.</p>
|
||||
<p>You have two ways to solve the previous issues:</p>
|
||||
<ul>
|
||||
<li>You can rename your serializer with a unique name and another name than "Serializer".</li>
|
||||
<li>You can set the <code>component_name</code> kwarg parameter of the AutoSchema constructor (see below).</li>
|
||||
<li>You can override the <code>get_component_name</code> method of the AutoSchema class (see below).</li>
|
||||
</ul>
|
||||
<h4 id="set-a-custom-components-name-for-your-view"><a class="toclink" href="#set-a-custom-components-name-for-your-view">Set a custom component's name for your view</a></h4>
|
||||
<p>To override the component's name in your view, you can use the <code>component_name</code> parameter of the AutoSchema constructor:</p>
|
||||
<pre><code class="python">from rest_framework.schemas.openapi import AutoSchema
|
||||
|
||||
class MyView(APIView):
|
||||
schema = AutoSchema(component_name="Ulysses")
|
||||
</code></pre>
|
||||
|
||||
<h4 id="override-the-default-implementation"><a class="toclink" href="#override-the-default-implementation">Override the default implementation</a></h4>
|
||||
<p>If you want to have more control and customization about how the schema's components are generated, you can override the <code>get_component_name</code> and <code>get_components</code> method from the AutoSchema class.</p>
|
||||
<pre><code class="python">from rest_framework.schemas.openapi import AutoSchema
|
||||
|
||||
class CustomSchema(AutoSchema):
|
||||
def get_components(self, path, method):
|
||||
# Implement your custom implementation
|
||||
|
||||
def get_component_name(self, serializer):
|
||||
# Implement your custom implementation
|
||||
"""
|
||||
AutoSchema subclass using schema_extra_info on the view.
|
||||
"""
|
||||
...
|
||||
|
||||
class CustomView(APIView):
|
||||
schema = CustomSchema()
|
||||
schema_extra_info = ... some extra info ...
|
||||
</code></pre>
|
||||
|
||||
<p>Here, the <code>AutoSchema</code> subclass goes looking for <code>schema_extra_info</code> on the
|
||||
view. This is <em>OK</em> (it doesn't actually hurt) but it means you'll end up with
|
||||
your schema logic spread out in a number of different places.</p>
|
||||
<p>Instead try to subclass <code>AutoSchema</code> such that the <code>extra_info</code> doesn't leak
|
||||
out into the view:</p>
|
||||
<pre><code class="python">class BaseSchema(AutoSchema):
|
||||
"""
|
||||
AutoSchema subclass that knows how to use extra_info.
|
||||
"""
|
||||
...
|
||||
|
||||
class CustomSchema(BaseSchema):
|
||||
extra_info = ... some extra info ...
|
||||
|
||||
class CustomView(APIView):
|
||||
"""APIView subclass with custom schema introspection."""
|
||||
schema = CustomSchema()
|
||||
</code></pre>
|
||||
|
||||
<p>This style is slightly more verbose but maintains the encapsulation of the
|
||||
schema related code. It's more <em>cohesive</em> in the <em>parlance</em>. It'll keep the
|
||||
rest of your API code more tidy.</p>
|
||||
<p>If an option applies to many view classes, rather than creating a specific
|
||||
subclass per-view, you may find it more convenient to allow specifying the
|
||||
option as an <code>__init__()</code> kwarg to your base <code>AutoSchema</code> subclass:</p>
|
||||
<pre><code class="python">class CustomSchema(BaseSchema):
|
||||
def __init__(self, **kwargs):
|
||||
# store extra_info for later
|
||||
self.extra_info = kwargs.pop("extra_info")
|
||||
super().__init__(**kwargs)
|
||||
|
||||
class CustomView(APIView):
|
||||
schema = CustomSchema(
|
||||
extra_info=... some extra info ...
|
||||
)
|
||||
</code></pre>
|
||||
|
||||
<p>This saves you having to create a custom subclass per-view for a commonly used option.</p>
|
||||
<p>Not all <code>AutoSchema</code> methods expose related <code>__init__()</code> kwargs, but those for
|
||||
the more commonly needed options do.</p>
|
||||
<h3 id="autoschema-methods"><a class="toclink" href="#autoschema-methods"><code>AutoSchema</code> methods</a></h3>
|
||||
<h4 id="get_components"><a class="toclink" href="#get_components"><code>get_components()</code></a></h4>
|
||||
<p>Generates the OpenAPI components that describe request and response bodies,
|
||||
deriving their properties from the serializer.</p>
|
||||
<p>Returns a dictionary mapping the component name to the generated
|
||||
representation. By default this has just a single pair but you may override
|
||||
<code>get_components()</code> to return multiple pairs if your view uses multiple
|
||||
serializers.</p>
|
||||
<h4 id="get_component_name"><a class="toclink" href="#get_component_name"><code>get_component_name()</code></a></h4>
|
||||
<p>Computes the component's name from the serializer.</p>
|
||||
<p>You may see warnings if your API has duplicate component names. If so you can override <code>get_component_name()</code> or pass the <code>component_name</code> <code>__init__()</code> kwarg (see below) to provide different names.</p>
|
||||
<h4 id="map_serializer"><a class="toclink" href="#map_serializer"><code>map_serializer()</code></a></h4>
|
||||
<p>Maps serializers to their OpenAPI representations.</p>
|
||||
<p>Most serializers should conform to the standard OpenAPI <code>object</code> type, but you may
|
||||
wish to override <code>map_serializer()</code> in order to customize this or other
|
||||
serializer-level fields.</p>
|
||||
<h4 id="map_field"><a class="toclink" href="#map_field"><code>map_field()</code></a></h4>
|
||||
<p>Maps individual serializer fields to their schema representation. The base implementation
|
||||
will handle the default fields that Django REST Framework provides.</p>
|
||||
<p>For <code>SerializerMethodField</code> instances, for which the schema is unknown, or custom field subclasses you should override <code>map_field()</code> to generate the correct schema:</p>
|
||||
<pre><code class="python">class CustomSchema(AutoSchema):
|
||||
"""Extension of ``AutoSchema`` to add support for custom field schemas."""
|
||||
|
||||
def map_field(self, field):
|
||||
# Handle SerializerMethodFields or custom fields here...
|
||||
# ...
|
||||
return super().map_field(field)
|
||||
</code></pre>
|
||||
|
||||
<p>Authors of third-party packages should aim to provide an <code>AutoSchema</code> subclass,
|
||||
and a mixin, overriding <code>map_field()</code> so that users can easily generate schemas
|
||||
for their custom fields.</p>
|
||||
<h4 id="get_tags"><a class="toclink" href="#get_tags"><code>get_tags()</code></a></h4>
|
||||
<p>OpenAPI groups operations by tags. By default tags taken from the first path
|
||||
segment of the routed URL. For example, a URL like <code>/users/{id}/</code> will generate
|
||||
the tag <code>users</code>.</p>
|
||||
<p>You can pass an <code>__init__()</code> kwarg to manually specify tags (see below), or
|
||||
override <code>get_tags()</code> to provide custom logic.</p>
|
||||
<h4 id="get_operation"><a class="toclink" href="#get_operation"><code>get_operation()</code></a></h4>
|
||||
<p>Returns the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#operationObject">OpenAPI operation object</a> that describes the
|
||||
endpoint, including path and query parameters for pagination, filtering, and so
|
||||
on.</p>
|
||||
<p>Together with <code>get_components()</code>, this is the main entry point to the view
|
||||
introspection.</p>
|
||||
<h4 id="get_operation_id"><a class="toclink" href="#get_operation_id"><code>get_operation_id()</code></a></h4>
|
||||
<p>There must be a unique <a href="openapi-operationid">operationid</a> for each operation.
|
||||
By default the <code>operationId</code> is deduced from the model name, serializer name or
|
||||
view name. The operationId looks like "listItems", "retrieveItem",
|
||||
"updateItem", etc. The <code>operationId</code> is camelCase by convention.</p>
|
||||
<h4 id="get_operation_id_base"><a class="toclink" href="#get_operation_id_base"><code>get_operation_id_base()</code></a></h4>
|
||||
<p>If you have several views with the same model name, you may see duplicate
|
||||
operationIds.</p>
|
||||
<p>In order to work around this, you can override <code>get_operation_id_base()</code> to
|
||||
provide a different base for name part of the ID.</p>
|
||||
<h3 id="autoschema__init__-kwargs"><a class="toclink" href="#autoschema__init__-kwargs"><code>AutoSchema.__init__()</code> kwargs</a></h3>
|
||||
<p><code>AutoSchema</code> provides a number of <code>__init__()</code> kwargs that can be used for
|
||||
common customizations, if the default generated values are not appropriate.</p>
|
||||
<p>The available kwargs are:</p>
|
||||
<ul>
|
||||
<li><code>tags</code>: Specify a list of tags.</li>
|
||||
<li><code>component_name</code>: Specify the component name.</li>
|
||||
<li><code>operation_id_base</code>: Specify the resource-name part of operation IDs.</li>
|
||||
</ul>
|
||||
<p>You pass the kwargs when declaring the <code>AutoSchema</code> instance on your view:</p>
|
||||
<pre><code>class PetDetailView(generics.RetrieveUpdateDestroyAPIView):
|
||||
schema = AutoSchema(
|
||||
tags=['Pets'],
|
||||
component_name='Pet',
|
||||
operation_id_base='Pet',
|
||||
)
|
||||
...
|
||||
</code></pre>
|
||||
|
||||
<p>Assuming a <code>Pet</code> model and <code>PetSerializer</code> serializer, the kwargs in this
|
||||
example are probably not needed. Often, though, you'll need to pass the kwargs
|
||||
if you have multiple view targeting the same model, or have multiple views with
|
||||
identically named serializers.</p>
|
||||
<p>If your views have related customizations that are needed frequently, you can
|
||||
create a base <code>AutoSchema</code> subclass for your project that takes additional
|
||||
<code>__init__()</code> kwargs to save subclassing <code>AutoSchema</code> for each view.</p>
|
||||
|
||||
|
||||
</div> <!--/span-->
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -617,6 +621,10 @@
|
|||
<a href="#drf-writable-nested">DRF Writable Nested</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#drf-encrypt-content">DRF Encrypt Content</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<div class="promo">
|
||||
|
@ -1096,7 +1104,7 @@ AccountSerializer():
|
|||
<p>The ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer.</p>
|
||||
<p>Normally if a <code>ModelSerializer</code> does not generate the fields you need by default then you should either add them to the class explicitly, or simply use a regular <code>Serializer</code> class instead. However in some cases you may want to create a new base class that defines how the serializer fields are created for any given model.</p>
|
||||
<h3 id="serializer_field_mapping"><a class="toclink" href="#serializer_field_mapping"><code>.serializer_field_mapping</code></a></h3>
|
||||
<p>A mapping of Django model classes to REST framework serializer classes. You can override this mapping to alter the default serializer classes that should be used for each model class.</p>
|
||||
<p>A mapping of Django model fields to REST framework serializer fields. You can override this mapping to alter the default serializer fields that should be used for each model field.</p>
|
||||
<h3 id="serializer_related_field"><a class="toclink" href="#serializer_related_field"><code>.serializer_related_field</code></a></h3>
|
||||
<p>This property should be the serializer field class, that is used for relational fields by default.</p>
|
||||
<p>For <code>ModelSerializer</code> this defaults to <code>PrimaryKeyRelatedField</code>.</p>
|
||||
|
@ -1532,6 +1540,8 @@ blacklisted and child serializers can be optionally expanded.</p>
|
|||
<p><a href="https://djangorestframework-queryfields.readthedocs.io/">djangorestframework-queryfields</a> allows API clients to specify which fields will be sent in the response via inclusion/exclusion query parameters.</p>
|
||||
<h2 id="drf-writable-nested"><a class="toclink" href="#drf-writable-nested">DRF Writable Nested</a></h2>
|
||||
<p>The <a href="https://github.com/beda-software/drf-writable-nested">drf-writable-nested</a> package provides writable nested model serializer which allows to create/update models with nested related data.</p>
|
||||
<h2 id="drf-encrypt-content"><a class="toclink" href="#drf-encrypt-content">DRF Encrypt Content</a></h2>
|
||||
<p>The <a href="https://github.com/oguzhancelikarslan/drf-encrypt-content">drf-encrypt-content</a> package helps you encrypt your data, serialized through ModelSerializer. It also contains some helper functions. Which helps you to encrypt your data. </p>
|
||||
|
||||
|
||||
</div> <!--/span-->
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -529,7 +533,7 @@ class ListUsers(APIView):
|
|||
<h2 id="dispatch-methods"><a class="toclink" href="#dispatch-methods">Dispatch methods</a></h2>
|
||||
<p>The following methods are called directly by the view's <code>.dispatch()</code> method.
|
||||
These perform any actions that need to occur before or after calling the handler methods such as <code>.get()</code>, <code>.post()</code>, <code>put()</code>, <code>patch()</code> and <code>.delete()</code>.</p>
|
||||
<h3 id="initialself-request-42args-kwargs"><a class="toclink" href="#initialself-request-42args-kwargs">.initial(self, request, *args, **kwargs)</a></h3>
|
||||
<h3 id="initialself-request-args-kwargs"><a class="toclink" href="#initialself-request-args-kwargs">.initial(self, request, *args, **kwargs)</a></h3>
|
||||
<p>Performs any actions that need to occur before the handler method gets called.
|
||||
This method is used to enforce permissions and throttling, and perform content negotiation.</p>
|
||||
<p>You won't typically need to override this method.</p>
|
||||
|
@ -537,10 +541,10 @@ This method is used to enforce permissions and throttling, and perform content n
|
|||
<p>Any exception thrown by the handler method will be passed to this method, which either returns a <code>Response</code> instance, or re-raises the exception.</p>
|
||||
<p>The default implementation handles any subclass of <code>rest_framework.exceptions.APIException</code>, as well as Django's <code>Http404</code> and <code>PermissionDenied</code> exceptions, and returns an appropriate error response.</p>
|
||||
<p>If you need to customize the error responses your API returns you should subclass this method.</p>
|
||||
<h3 id="initialize_requestself-request-42args-kwargs"><a class="toclink" href="#initialize_requestself-request-42args-kwargs">.initialize_request(self, request, *args, **kwargs)</a></h3>
|
||||
<h3 id="initialize_requestself-request-args-kwargs"><a class="toclink" href="#initialize_requestself-request-args-kwargs">.initialize_request(self, request, *args, **kwargs)</a></h3>
|
||||
<p>Ensures that the request object that is passed to the handler method is an instance of <code>Request</code>, rather than the usual Django <code>HttpRequest</code>.</p>
|
||||
<p>You won't typically need to override this method.</p>
|
||||
<h3 id="finalize_responseself-request-response-42args-kwargs"><a class="toclink" href="#finalize_responseself-request-response-42args-kwargs">.finalize_response(self, request, response, *args, **kwargs)</a></h3>
|
||||
<h3 id="finalize_responseself-request-response-args-kwargs"><a class="toclink" href="#finalize_responseself-request-response-args-kwargs">.finalize_response(self, request, response, *args, **kwargs)</a></h3>
|
||||
<p>Ensures that any <code>Response</code> object returned from the handler method will be rendered into the correct content type, as determined by the content negotiation.</p>
|
||||
<p>You won't typically need to override this method.</p>
|
||||
<hr />
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -579,7 +583,7 @@ def create(self, validated_data):
|
|||
<p>The reason behind this is that Django's <code>ValidationError</code> class is intended for use with HTML forms and its API makes using it slightly awkward with nested validation errors that can occur in serializers.</p>
|
||||
<p>For most users this change shouldn't require any updates to your codebase, but it is worth ensuring that whenever raising validation errors you should prefer using the <code>serializers.ValidationError</code> exception class, and not Django's built-in exception.</p>
|
||||
<p>We strongly recommend that you use the namespaced import style of <code>import serializers</code> and not <code>from serializers import ValidationError</code> in order to avoid any potential confusion.</p>
|
||||
<h4 id="change-to-validate_ltfield_namegt"><a class="toclink" href="#change-to-validate_ltfield_namegt">Change to <code>validate_<field_name></code>.</a></h4>
|
||||
<h4 id="change-to-validate_field_name"><a class="toclink" href="#change-to-validate_field_name">Change to <code>validate_<field_name></code>.</a></h4>
|
||||
<p>The <code>validate_<field_name></code> method hooks that can be attached to serializer classes change their signature slightly and return type. Previously these would take a dictionary of all incoming data, and a key representing the field name, and would return a dictionary including the validated data for that field:</p>
|
||||
<pre><code>def validate_score(self, attrs, source):
|
||||
if attrs['score'] % 10 != 0:
|
||||
|
@ -605,7 +609,7 @@ def create(self, validated_data):
|
|||
raise serializers.ValidationError({'my_field': 'A field error'})
|
||||
</code></pre>
|
||||
<p>This ensures you can still write validation that compares all the input fields, but that marks the error against a particular field.</p>
|
||||
<h4 id="removal-of-transform_ltfield_namegt"><a class="toclink" href="#removal-of-transform_ltfield_namegt">Removal of <code>transform_<field_name></code>.</a></h4>
|
||||
<h4 id="removal-of-transform_field_name"><a class="toclink" href="#removal-of-transform_field_name">Removal of <code>transform_<field_name></code>.</a></h4>
|
||||
<p>The under-used <code>transform_<field_name></code> on serializer classes is no longer provided. Instead you should just override <code>to_representation()</code> if you need to apply any modifications to the representation style.</p>
|
||||
<p>For example:</p>
|
||||
<pre><code>def to_representation(self, instance):
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../3.10-announcement/">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../release-notes/">
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../3.12-announcement/">
|
||||
<i class="icon-arrow-left icon-white"></i> Previous
|
||||
</a>
|
||||
<a id="search_modal_show" class="repo-link btn btn-inverse btn-small" href="#mkdocs_search_modal" data-toggle="modal" data-target="#mkdocs_search_modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li class="active" >
|
||||
<a href="./">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
664
community/3.12-announcement/index.html
Normal file
|
@ -0,0 +1,664 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta charset="utf-8">
|
||||
<title>3.12 Announcement - Django REST framework</title>
|
||||
<link href="../../img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<link rel="canonical" href="https://www.django-rest-framework.org/community/3.12-announcement/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, 3.12 Announcement">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="../../css/prettify.css" rel="stylesheet">
|
||||
<link href="../../css/bootstrap.css" rel="stylesheet">
|
||||
<link href="../../css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="../../css/default.css" rel="stylesheet">
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script');
|
||||
ga.type = 'text/javascript';
|
||||
ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#sidebarInclude img {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#sidebarInclude a.promo {
|
||||
color: black;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
div.promo {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="-page">
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/encode/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../3.11-announcement/">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../release-notes/">
|
||||
<i class="icon-arrow-left icon-white"></i> Previous
|
||||
</a>
|
||||
<a id="search_modal_show" class="repo-link btn btn-inverse btn-small" href="#mkdocs_search_modal" data-toggle="modal" data-target="#mkdocs_search_modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
<a class="brand" href="https://www.django-rest-framework.org/">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
|
||||
<!-- Main navigation -->
|
||||
<ul class="nav navbar-nav">
|
||||
|
||||
<li >
|
||||
<a href="../..">Home</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/quickstart/">Quickstart</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/1-serialization/">1 - Serialization</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/2-requests-and-responses/">2 - Requests and responses</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/3-class-based-views/">3 - Class based views</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/4-authentication-and-permissions/">4 - Authentication and permissions</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/5-relationships-and-hyperlinked-apis/">5 - Relationships and hyperlinked APIs</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/6-viewsets-and-routers/">6 - Viewsets and routers</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/requests/">Requests</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/responses/">Responses</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/views/">Views</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/generic-views/">Generic views</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/viewsets/">Viewsets</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/routers/">Routers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/parsers/">Parsers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/renderers/">Renderers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/serializers/">Serializers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/fields/">Serializer fields</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/relations/">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators/">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication/">Authentication</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/permissions/">Permissions</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/caching/">Caching</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/throttling/">Throttling</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/filtering/">Filtering</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/pagination/">Pagination</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/versioning/">Versioning</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/content-negotiation/">Content negotiation</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/metadata/">Metadata</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/schemas/">Schemas</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/format-suffixes/">Format suffixes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/reverse/">Returning URLs</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/exceptions/">Exceptions</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/status-codes/">Status codes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/testing/">Testing</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/settings/">Settings</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<li >
|
||||
<a href="../../topics/documenting-your-api/">Documenting your API</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/api-clients/">API Clients</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/internationalization/">Internationalization</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/ajax-csrf-cors/">AJAX, CSRF & CORS</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/html-and-forms/">HTML & Forms</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/browser-enhancements/">Browser Enhancements</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/browsable-api/">The Browsable API</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/rest-hypermedia-hateoas/">REST, Hypermedia & HATEOAS</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown active">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Community <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<li >
|
||||
<a href="../tutorials-and-resources/">Tutorials and Resources</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../third-party-packages/">Third Party Packages</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../contributing/">Contributing to REST framework</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../project-management/">Project management</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li class="active" >
|
||||
<a href="./">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.10-announcement/">3.10 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.9-announcement/">3.9 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.8-announcement/">3.8 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.7-announcement/">3.7 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.6-announcement/">3.6 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.5-announcement/">3.5 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.4-announcement/">3.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.3-announcement/">3.3 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.2-announcement/">3.2 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.1-announcement/">3.1 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement/">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement/">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../mozilla-grant/">Mozilla Grant</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../funding/">Funding</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../jobs/">Jobs</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<!--/.nav-collapse -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
<!-- Search Modal -->
|
||||
<div id="mkdocs_search_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form role="form" autocomplete="off">
|
||||
<div class="form-group">
|
||||
<input type="text" name="q" class="form-control" placeholder="Search..." id="mkdocs-search-query">
|
||||
</div>
|
||||
</form>
|
||||
<div id="mkdocs-search-results"></div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span3">
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#django-rest-framework-312">Django REST framework 3.12</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#grouping-operations-with-tags">Grouping operations with tags.</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#customizing-the-operation-id">Customizing the operation ID.</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#support-for-openapi-components">Support for OpenAPI components.</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#more-public-api">More Public API</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#support-for-jsonfield">Support for JSONField.</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#searchfilter-improvements">SearchFilter improvements</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#funding">Funding</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<div class="promo">
|
||||
<hr/>
|
||||
<div id="sidebarInclude">
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
.promo li a {
|
||||
float: left;
|
||||
width: 130px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
margin: 10px 30px;
|
||||
padding: 150px 0 0 0;
|
||||
background-position: 0 50%;
|
||||
background-size: 130px auto;
|
||||
background-repeat: no-repeat;
|
||||
font-size: 120%;
|
||||
color: black;
|
||||
}
|
||||
.promo li {
|
||||
list-style: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1 id="django-rest-framework-312"><a class="toclink" href="#django-rest-framework-312">Django REST framework 3.12</a></h1>
|
||||
<p>REST framework 3.12 brings a handful of refinements to the OpenAPI schema
|
||||
generation, plus support for Django's new database-agnostic <code>JSONField</code>,
|
||||
and some improvements to the <code>SearchFilter</code> class.</p>
|
||||
<h2 id="grouping-operations-with-tags"><a class="toclink" href="#grouping-operations-with-tags">Grouping operations with tags.</a></h2>
|
||||
<p>Open API schemas will now automatically include tags, based on the first element
|
||||
in the URL path.</p>
|
||||
<p>For example...</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Method</th>
|
||||
<th>Path</th>
|
||||
<th>Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>GET</code>, <code>PUT</code>, <code>PATCH</code>, <code>DELETE</code></td>
|
||||
<td><code>/users/{id}/</code></td>
|
||||
<td><code>['users']</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET</code>, <code>POST</code></td>
|
||||
<td><code>/users/</code></td>
|
||||
<td><code>['users']</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET</code>, <code>PUT</code>, <code>PATCH</code>, <code>DELETE</code></td>
|
||||
<td><code>/orders/{id}/</code></td>
|
||||
<td><code>['orders']</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET</code>, <code>POST</code></td>
|
||||
<td><code>/orders/</code></td>
|
||||
<td><code>['orders']</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The tags used for a particular view may also be overridden...</p>
|
||||
<pre><code class="python">class MyOrders(APIView):
|
||||
schema = AutoSchema(tags=['users', 'orders'])
|
||||
...
|
||||
</code></pre>
|
||||
|
||||
<p>See <a href="https://www.django-rest-framework.org/api-guide/schemas/#grouping-operations-with-tags">the schema documentation</a> for more information.</p>
|
||||
<h2 id="customizing-the-operation-id"><a class="toclink" href="#customizing-the-operation-id">Customizing the operation ID.</a></h2>
|
||||
<p>REST framework automatically determines operation IDs to use in OpenAPI
|
||||
schemas. The latest version provides more control for overriding the behaviour
|
||||
used to generate the operation IDs.</p>
|
||||
<p>See <a href="https://www.django-rest-framework.org/api-guide/schemas/#operationid">the schema documentation</a> for more information.</p>
|
||||
<h2 id="support-for-openapi-components"><a class="toclink" href="#support-for-openapi-components">Support for OpenAPI components.</a></h2>
|
||||
<p>In order to output more graceful OpenAPI schemes, REST framework 3.12 now
|
||||
defines components in the schema, and then references them inside request
|
||||
and response objects. This is in contrast with the previous approach, which
|
||||
fully expanded the request and response bodies for each operation.</p>
|
||||
<p>The names used for a component default to using the serializer class name, <a href="https://www.django-rest-framework.org/api-guide/schemas/#components">but
|
||||
may be overridden if needed</a>...</p>
|
||||
<pre><code class="python">class MyOrders(APIView):
|
||||
schema = AutoSchema(component_name="OrderDetails")
|
||||
</code></pre>
|
||||
|
||||
<h2 id="more-public-api"><a class="toclink" href="#more-public-api">More Public API</a></h2>
|
||||
<p>Many methods on the <code>AutoSchema</code> class have now been promoted to public API,
|
||||
allowing you to more fully customize the schema generation. The following methods
|
||||
are now available for overriding...</p>
|
||||
<ul>
|
||||
<li><code>get_path_parameters</code></li>
|
||||
<li><code>get_pagination_parameters</code></li>
|
||||
<li><code>get_filter_parameters</code></li>
|
||||
<li><code>get_request_body</code></li>
|
||||
<li><code>get_responses</code></li>
|
||||
<li><code>get_serializer</code></li>
|
||||
<li><code>get_paginator</code></li>
|
||||
<li><code>map_serializer</code></li>
|
||||
<li><code>map_field</code></li>
|
||||
<li><code>map_choice_field</code></li>
|
||||
<li><code>map_field_validators</code></li>
|
||||
<li><code>allows_filters</code>.</li>
|
||||
</ul>
|
||||
<p>See <a href="https://www.django-rest-framework.org/api-guide/schemas/#per-view-customization">the schema docs</a>
|
||||
for details on using custom <code>AutoSchema</code> subclasses.</p>
|
||||
<h2 id="support-for-jsonfield"><a class="toclink" href="#support-for-jsonfield">Support for JSONField.</a></h2>
|
||||
<p>Django 3.1 deprecated the existing <code>django.contrib.postgres.fields.JSONField</code>
|
||||
in favour of a new database-agnositic <code>JSONField</code>.</p>
|
||||
<p>REST framework 3.12 now supports this new model field, and <code>ModelSerializer</code>
|
||||
classes will correctly map the model field.</p>
|
||||
<h2 id="searchfilter-improvements"><a class="toclink" href="#searchfilter-improvements">SearchFilter improvements</a></h2>
|
||||
<p>There are a couple of significant improvements to the <code>SearchFilter</code> class.</p>
|
||||
<h3 id="nested-searches-against-jsonfield-and-hstorefield"><a class="toclink" href="#nested-searches-against-jsonfield-and-hstorefield">Nested searches against JSONField and HStoreField</a></h3>
|
||||
<p>The class now supports nested search within <code>JSONField</code> and <code>HStoreField</code>, using
|
||||
the double underscore notation for traversing which element of the field the
|
||||
search should apply to.</p>
|
||||
<pre><code class="python">class SitesSearchView(generics.ListAPIView):
|
||||
"""
|
||||
An API view to return a list of archaeological sites, optionally filtered
|
||||
by a search against the site name or location. (Location searches are
|
||||
matched against the region and country names.)
|
||||
"""
|
||||
queryset = Sites.objects.all()
|
||||
serializer_class = SitesSerializer
|
||||
filter_backends = [filters.SearchFilter]
|
||||
search_fields = ['site_name', 'location__region', 'location__country']
|
||||
</code></pre>
|
||||
|
||||
<h3 id="searches-against-annotate-fields"><a class="toclink" href="#searches-against-annotate-fields">Searches against annotate fields</a></h3>
|
||||
<p>Django allows querysets to create additional virtual fields, using the <code>.annotate</code>
|
||||
method. We now support searching against annotate fields.</p>
|
||||
<pre><code class="python">class PublisherSearchView(generics.ListAPIView):
|
||||
"""
|
||||
Search for publishers, optionally filtering the search against the average
|
||||
rating of all their books.
|
||||
"""
|
||||
queryset = Publisher.objects.annotate(avg_rating=Avg('book__rating'))
|
||||
serializer_class = PublisherSerializer
|
||||
filter_backends = [filters.SearchFilter]
|
||||
search_fields = ['avg_rating']
|
||||
</code></pre>
|
||||
|
||||
<hr />
|
||||
<h2 id="funding"><a class="toclink" href="#funding">Funding</a></h2>
|
||||
<p>REST framework is a <em>collaboratively funded project</em>. If you use
|
||||
REST framework commercially we strongly encourage you to invest in its
|
||||
continued development by <strong><a href="../funding/">signing up for a paid plan</a></strong>.</p>
|
||||
<p><em>Every single sign-up helps us make REST framework long-term financially sustainable.</em></p>
|
||||
<ul class="premium-promo promo">
|
||||
<li><a href="https://getsentry.com/welcome/" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/sentry130.png)">Sentry</a></li>
|
||||
<li><a href="https://getstream.io/try-the-api/?utm_source=drf&utm_medium=banner&utm_campaign=drf" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/stream-130.png)">Stream</a></li>
|
||||
<li><a href="https://software.esg-usa.com" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/esg-new-logo.png)">ESG</a></li>
|
||||
<li><a href="https://rollbar.com" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/rollbar2.png)">Rollbar</a></li>
|
||||
<li><a href="https://cadre.com" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/cadre.png)">Cadre</a></li>
|
||||
<li><a href="https://hubs.ly/H0f30Lf0" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/kloudless-plus-text.png)">Kloudless</a></li>
|
||||
<li><a href="https://lightsonsoftware.com" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/lightson-dark.png)">Lights On Software</a></li>
|
||||
<li><a href="https://retool.com/?utm_source=djangorest&utm_medium=sponsorship" style="background-image: url(https://fund-rest-framework.s3.amazonaws.com/retool-sidebar.png)">Retool</a></li>
|
||||
</ul>
|
||||
|
||||
<div style="clear: both; padding-bottom: 20px;"></div>
|
||||
|
||||
<p><em>Many thanks to all our <a href="https://fund.django-rest-framework.org/topics/funding/#our-sponsors">wonderful sponsors</a>, and in particular to our premium backers, <a href="https://getsentry.com/welcome/">Sentry</a>, <a href="https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf">Stream</a>, <a href="https://software.esg-usa.com/">ESG</a>, <a href="https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial">Rollbar</a>, <a href="https://cadre.com">Cadre</a>, <a href="https://hubs.ly/H0f30Lf0">Kloudless</a>, <a href="https://lightsonsoftware.com">Lights On Software</a>, and <a href="https://retool.com/?utm_source=djangorest&utm_medium=sponsorship">Retool</a>.</em></p>
|
||||
|
||||
|
||||
</div> <!--/span-->
|
||||
</div> <!--/row-->
|
||||
</div> <!--/.fluid-container-->
|
||||
</div> <!--/.body content-->
|
||||
<div id="push"></div>
|
||||
</div> <!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script async src="https://fund.django-rest-framework.org/sidebar_include.js"></script>
|
||||
<script src="../../js/jquery-1.8.1-min.js"></script>
|
||||
<script src="../../js/prettify-1.0.js"></script>
|
||||
<script src="../../js/bootstrap-2.1.1-min.js"></script>
|
||||
<script src="../../js/theme.js"></script>
|
||||
|
||||
<script>var base_url = '../..';</script>
|
||||
|
||||
<script src="../../search/main.js" defer></script>
|
||||
|
||||
|
||||
<script>
|
||||
var shiftWindow = function() {
|
||||
scrollBy(0, -50)
|
||||
};
|
||||
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav/dropdown to no higher than browser window
|
||||
$('.side-nav, .dropdown-menu').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function() {
|
||||
$(window).resize(function() {
|
||||
$('.side-nav, .dropdown-menu').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -521,7 +525,7 @@ schema_view = get_schema_view(
|
|||
)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^swagger/$', schema_view),
|
||||
path('swagger/', schema_view),
|
||||
...
|
||||
]
|
||||
</code></pre>
|
||||
|
@ -618,8 +622,8 @@ from my_project.routers import router
|
|||
schema_view = get_schema_view(title='Example API')
|
||||
|
||||
urlpatterns = [
|
||||
url('^$', schema_view),
|
||||
url(r'^', include(router.urls)),
|
||||
path('', schema_view),
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
</code></pre>
|
||||
<h3 id="schema-path-representations"><a class="toclink" href="#schema-path-representations">Schema path representations</a></h3>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -508,7 +512,7 @@ API_DESCRIPTION = '...'
|
|||
|
||||
urlpatterns = [
|
||||
...
|
||||
url(r'^docs/', include_docs_urls(title=API_TITLE, description=API_DESCRIPTION))
|
||||
path('docs/', include_docs_urls(title=API_TITLE, description=API_DESCRIPTION))
|
||||
]
|
||||
</code></pre>
|
||||
<p>Once installed you should see something a little like this:</p>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -505,6 +509,7 @@ the schema into your repository.</li>
|
|||
<p>Here's an example of adding an OpenAPI schema to the URL conf:</p>
|
||||
<pre><code class="python">from rest_framework.schemas import get_schema_view
|
||||
from rest_framework.renderers import JSONOpenAPIRenderer
|
||||
from django.urls import path
|
||||
|
||||
schema_view = get_schema_view(
|
||||
title='Server Monitoring API',
|
||||
|
@ -513,7 +518,7 @@ schema_view = get_schema_view(
|
|||
)
|
||||
|
||||
urlpatterns = [
|
||||
url('^schema.json$', schema_view),
|
||||
path('schema.json', schema_view),
|
||||
...
|
||||
]
|
||||
</code></pre>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/encode/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../3.11-announcement/">
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../3.12-announcement/">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../project-management/">
|
||||
|
@ -293,6 +293,10 @@
|
|||
<a href="./">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -421,6 +425,10 @@
|
|||
<a href="#311x-series">3.11.x series</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#311x-series_1">3.11.x series</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#310x-series">3.10.x series</a>
|
||||
</li>
|
||||
|
@ -509,10 +517,55 @@
|
|||
</code></pre>
|
||||
<hr />
|
||||
<h2 id="311x-series"><a class="toclink" href="#311x-series">3.11.x series</a></h2>
|
||||
<h3 id="3120"><a class="toclink" href="#3120">3.12.0</a></h3>
|
||||
<ul>
|
||||
<li>Add <code>--file</code> option to <code>generateschema</code> command. [#7130]</li>
|
||||
<li>Support <code>tags</code> for OpenAPI schema generation. See <a href="https://www.django-rest-framework.org/api-guide/schemas/#grouping-operations-with-tags">the schema docs</a>. [#7184]</li>
|
||||
<li>Support customising the operation ID for schema generation. See <a href="https://www.django-rest-framework.org/api-guide/schemas/#operationid">the schema docs</a>. [#7190]</li>
|
||||
<li>Support OpenAPI components for schema generation. See <a href="https://www.django-rest-framework.org/api-guide/schemas/#components">the schema docs</a>. [#7124]</li>
|
||||
<li>The following methods on <code>AutoSchema</code> become public API: <code>get_path_parameters</code>, <code>get_pagination_parameters</code>, <code>get_filter_parameters</code>, <code>get_request_body</code>, <code>get_responses</code>, <code>get_serializer</code>, <code>get_paginator</code>, <code>map_serializer</code>, <code>map_field</code>, <code>map_choice_field</code>, <code>map_field_validators</code>, <code>allows_filters</code>. See <a href="https://www.django-rest-framework.org/api-guide/schemas/#autoschema">the schema docs</a></li>
|
||||
<li>Add support for Django 3.1's database-agnositic <code>JSONField</code>. [#7467]</li>
|
||||
<li><code>SearchFilter</code> now supports nested search on <code>JSONField</code> and <code>HStoreField</code> model fields. [#7121]</li>
|
||||
<li><code>SearchFilter</code> now supports searching on <code>annotate()</code> fields. [#6240]</li>
|
||||
<li>The authtoken model no longer exposes the <code>pk</code> in the admin URL. [#7341]</li>
|
||||
<li>Add <code>__repr__</code> for Request instances. [#7239]</li>
|
||||
<li>UTF-8 decoding with Latin-1 fallback for basic auth credentials. [#7193]</li>
|
||||
<li>CharField treats surrogate characters as a validation failure. [#7026]</li>
|
||||
<li>Don't include callables as default values in schemas. [#7105]</li>
|
||||
<li>Improve <code>ListField</code> schema output to include all available child information. [#7137]</li>
|
||||
<li>Allow <code>default=False</code> to be included for <code>BooleanField</code> schema outputs. [#7165]</li>
|
||||
<li>Include <code>"type"</code> information in <code>ChoiceField</code> schema outputs. [#7161]</li>
|
||||
<li>Include <code>"type": "object"</code> on schema objects. [#7169]</li>
|
||||
<li>Don't include component in schema output for DELETE requests. [#7229]</li>
|
||||
<li>Fix schema types for <code>DecimalField</code>. [#7254]</li>
|
||||
<li>Fix schema generation for <code>ObtainAuthToken</code> view. [#7211]</li>
|
||||
<li>Support passing <code>context=...</code> to view <code>.get_serializer()</code> methods. [#7298]</li>
|
||||
<li>Pass custom code to <code>PermissionDenied</code> if permission class has one set. [#7306]</li>
|
||||
<li>Include "example" in schema pagination output. [#7275]</li>
|
||||
<li>Default status code of 201 on schema output for POST requests. [#7206]</li>
|
||||
<li>Use camelCase for operation IDs in schema output. [#7208]</li>
|
||||
<li>Warn if duplicate operation IDs exist in schema output. [#7207]</li>
|
||||
<li>Improve handling of decimal type when mapping <code>ChoiceField</code> to a schema output. [#7264]</li>
|
||||
<li>Disable YAML aliases for OpenAPI schema outputs. [#7131]</li>
|
||||
<li>Fix action URL names for APIs included under a namespaced URL. [#7287]</li>
|
||||
<li>Update jQuery version from 3.4 to 3.5. [#7313]</li>
|
||||
<li>Fix <code>UniqueTogether</code> handling when serializer fields use <code>source=...</code>. [#7143]</li>
|
||||
<li>HTTP <code>HEAD</code> requests now set <code>self.action</code> correctly on a ViewSet instance. [#7223]</li>
|
||||
<li>Return a valid OpenAPI schema for the case where no API schema paths exist. [#7125]</li>
|
||||
<li>Include tests in package distribution. [#7145]</li>
|
||||
<li>Allow type checkers to support annotations like <code>ModelSerializer[Author]</code>. [#7385]</li>
|
||||
<li>Don't include invalid <code>charset=None</code> portion in the request <code>Content-Type</code> header when using APIClient. [#7400]</li>
|
||||
<li>Fix <code>\Z</code>/<code>\z</code> tokens in OpenAPI regexs. [#7389]</li>
|
||||
<li>Fix <code>PrimaryKeyRelatedField</code> and <code>HyperlinkedRelatedField</code> when source field is actually a property. [#7142]</li>
|
||||
<li><code>Token.generate_key</code> is now a class method. [#7502]</li>
|
||||
<li><code>@action</code> warns if method is wrapped in a decorator that does not preserve information using <code>@functools.wraps</code>. [#7098]</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="311x-series_1"><a class="toclink" href="#311x-series_1">3.11.x series</a></h2>
|
||||
<h3 id="3110"><a class="toclink" href="#3110">3.11.0</a></h3>
|
||||
<p><strong>Date</strong>: 12th December 2019</p>
|
||||
<ul>
|
||||
<li>Drop <code>.set_context</code> API <a href="../3.11-announcement#validator-default-context">in favour of a <code>requires_context</code> marker</a>.</li>
|
||||
<li>Drop <code>.set_context</code> API <a href="../3.11-announcement/#validator-default-context">in favour of a <code>requires_context</code> marker</a>.</li>
|
||||
<li>Changed default widget for TextField with choices to select box. <a href="https://github.com/encode/django-rest-framework/issues/6892">#6892</a></li>
|
||||
<li>Supported nested writes on non-relational fields, such as JSONField. <a href="https://github.com/encode/django-rest-framework/issues/6916">#6916</a></li>
|
||||
<li>Include request/response media types in OpenAPI schemas, based on configured parsers/renderers. <a href="https://github.com/encode/django-rest-framework/issues/6865">#6865</a></li>
|
||||
|
@ -644,7 +697,7 @@ Be sure to upgrade to Python 3 before upgrading to Django REST Framework 3.10.</
|
|||
<li>Fixed Javascript <code>e.indexOf</code> is not a function error <a href="https://github.com/encode/django-rest-framework/issues/5982">#5982</a></li>
|
||||
<li>Fix schemas for extra actions <a href="https://github.com/encode/django-rest-framework/issues/5992">#5992</a></li>
|
||||
<li>Improved get_error_detail to use error_dict/error_list <a href="https://github.com/encode/django-rest-framework/issues/5785">#5785</a></li>
|
||||
<li>Imprvied URLs in Admin renderer <a href="https://github.com/encode/django-rest-framework/issues/5988">#5988</a></li>
|
||||
<li>Improved URLs in Admin renderer <a href="https://github.com/encode/django-rest-framework/issues/5988">#5988</a></li>
|
||||
<li>Add "Community" section to docs, minor cleanup <a href="https://github.com/encode/django-rest-framework/issues/5993">#5993</a></li>
|
||||
<li>Moved guardian imports out of compat <a href="https://github.com/encode/django-rest-framework/issues/6054">#6054</a></li>
|
||||
<li>Deprecate the <code>DjangoObjectPermissionsFilter</code> class, moved to the <code>djangorestframework-guardian</code> package. <a href="https://github.com/encode/django-rest-framework/issues/6075">#6075</a></li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -566,8 +570,9 @@ You probably want to also tag the version now:
|
|||
<li><a href="https://github.com/kevin-brown/drf-any-permissions">drf-any-permissions</a> - Provides alternative permission handling.</li>
|
||||
<li><a href="https://github.com/niwibe/djangorestframework-composed-permissions">djangorestframework-composed-permissions</a> - Provides a simple way to define complex permissions.</li>
|
||||
<li><a href="https://github.com/caxap/rest_condition">rest_condition</a> - Another extension for building complex permissions in a simple and convenient way.</li>
|
||||
<li><a href="https://github.com/Helioscene/dry-rest-permissions">dry-rest-permissions</a> - Provides a simple way to define permissions for individual api actions.</li>
|
||||
<li><a href="https://github.com/FJNR-inc/dry-rest-permissions">dry-rest-permissions</a> - Provides a simple way to define permissions for individual api actions.</li>
|
||||
<li><a href="https://github.com/rsinger86/drf-access-policy">drf-access-policy</a> - Declarative and flexible permissions inspired by AWS' IAM policies.</li>
|
||||
<li><a href="https://github.com/drf-psq/drf-psq">drf-psq</a> - An extension that gives support for having action-based <strong>permission_classes</strong>, <strong>serializer_class</strong>, and <strong>queryset</strong> dependent on permission-based rules.</li>
|
||||
</ul>
|
||||
<h3 id="serializers"><a class="toclink" href="#serializers">Serializers</a></h3>
|
||||
<ul>
|
||||
|
@ -610,7 +615,7 @@ You probably want to also tag the version now:
|
|||
<ul>
|
||||
<li><a href="https://github.com/mjumbewu/django-rest-framework-csv">djangorestframework-csv</a> - Provides CSV renderer support.</li>
|
||||
<li><a href="https://github.com/django-json-api/django-rest-framework-json-api">djangorestframework-jsonapi</a> - Provides a parser, renderer, serializers, and other tools to help build an API that is compliant with the jsonapi.org spec.</li>
|
||||
<li><a href="https://github.com/gizmag/drf-ujson-renderer">drf_ujson</a> - Implements JSON rendering using the UJSON package.</li>
|
||||
<li><a href="https://github.com/Amertz08/drf_ujson2">drf_ujson2</a> - Implements JSON rendering using the UJSON package.</li>
|
||||
<li><a href="https://github.com/wq/django-rest-pandas">rest-pandas</a> - Pandas DataFrame-powered renderers including Excel, CSV, and SVG formats.</li>
|
||||
<li><a href="https://github.com/allisson/django-rest-framework-rapidjson">djangorestframework-rapidjson</a> - Provides rapidjson support with parser and renderer.</li>
|
||||
</ul>
|
||||
|
@ -644,6 +649,7 @@ You probably want to also tag the version now:
|
|||
<li><a href="https://github.com/fvlima/drf-viewset-profiler">drf-viewset-profiler</a> - Lib to profile all methods from a viewset line by line.</li>
|
||||
<li><a href="https://github.com/cloudcode-hungary/django-rest-framework-features/">djangorestframework-features</a> - Advanced schema generation and more based on named features.</li>
|
||||
<li><a href="https://github.com/barseghyanartur/django-elasticsearch-dsl-drf">django-elasticsearch-dsl-drf</a> - Integrate Elasticsearch DSL with Django REST framework. Package provides views, serializers, filter backends, pagination and other handy add-ons.</li>
|
||||
<li><a href="https://github.com/rhenter/django-api-client">django-api-client</a> - DRF client that groups the Endpoint response, for use in CBVs and FBV as if you were working with Django's Native Models..</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -452,7 +456,7 @@ are optional but recommended.</p>
|
|||
|
||||
urlpatterns = [
|
||||
...
|
||||
url(r'^docs/', include_docs_urls(title='My API title'))
|
||||
path('docs/', include_docs_urls(title='My API title'))
|
||||
]
|
||||
</code></pre>
|
||||
<p>This will include two different views:</p>
|
||||
|
@ -470,7 +474,7 @@ This means that views will not be instantiated with a <code>request</code> insta
|
|||
urlpatterns = [
|
||||
...
|
||||
# Generate schema with valid `request` instance:
|
||||
url(r'^docs/', include_docs_urls(title='My API title', public=False))
|
||||
path('docs/', include_docs_urls(title='My API title', public=False))
|
||||
]
|
||||
</code></pre>
|
||||
<hr />
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="index-page">
|
||||
<body onload="prettyPrint()" class="-page">
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
|
@ -293,6 +293,10 @@
|
|||
<a href="../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -398,13 +402,9 @@
|
|||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
|
||||
<li class="main">
|
||||
<a href="#">Django REST framework</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<li class="">
|
||||
<li class="main">
|
||||
<a href="#legacy-coreapi-schemas-docs">Legacy CoreAPI Schemas Docs</a>
|
||||
</li>
|
||||
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -503,6 +507,10 @@
|
|||
<a href="#drf-yasg-yet-another-swagger-generator">drf-yasg - Yet Another Swagger Generator</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#drf-spectacular-sane-and-flexible-openapi-30-schema-generation-for-django-rest-framework">drf-spectacular - Sane and flexible OpenAPI 3.0 schema generation for Django REST framework</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<div class="promo">
|
||||
|
@ -589,11 +597,12 @@ with each new release, or serve the API schema from your site's static media.</p
|
|||
<h3 id="adding-a-view-with-get_schema_view"><a class="toclink" href="#adding-a-view-with-get_schema_view">Adding a view with <code>get_schema_view</code></a></h3>
|
||||
<p>To add a dynamically generated schema view to your API, use <code>get_schema_view</code>.</p>
|
||||
<pre><code class="python">from rest_framework.schemas import get_schema_view
|
||||
from django.urls import path
|
||||
|
||||
schema_view = get_schema_view(title="Example API")
|
||||
|
||||
urlpatterns = [
|
||||
url('^schema$', schema_view),
|
||||
path('schema', schema_view),
|
||||
...
|
||||
]
|
||||
</code></pre>
|
||||
|
@ -798,7 +807,7 @@ exactly what you need.</p>
|
|||
schema_view = get_schema_view(title="Server Monitoring API")
|
||||
|
||||
urlpatterns = [
|
||||
url('^$', schema_view),
|
||||
path('', schema_view),
|
||||
...
|
||||
]
|
||||
</code></pre>
|
||||
|
@ -852,7 +861,7 @@ schema_view = get_schema_view(
|
|||
<p>List of url patterns to limit the schema introspection to. If you only want the <code>myproject.api</code> urls
|
||||
to be exposed in the schema:</p>
|
||||
<pre><code>schema_url_patterns = [
|
||||
url(r'^api/', include('myproject.api.urls')),
|
||||
path('api/', include('myproject.api.urls')),
|
||||
]
|
||||
|
||||
schema_view = get_schema_view(
|
||||
|
@ -893,7 +902,7 @@ def schema_view(request):
|
|||
</code></pre>
|
||||
<p><strong>urls.py:</strong></p>
|
||||
<pre><code>urlpatterns = [
|
||||
url('/', schema_view),
|
||||
path('', schema_view),
|
||||
...
|
||||
]
|
||||
</code></pre>
|
||||
|
@ -1190,6 +1199,9 @@ Valid only if a <code>location="body"</code> field is included on the <code>Link
|
|||
<h2 id="drf-yasg-yet-another-swagger-generator"><a class="toclink" href="#drf-yasg-yet-another-swagger-generator">drf-yasg - Yet Another Swagger Generator</a></h2>
|
||||
<p><a href="https://github.com/axnsan12/drf-yasg/">drf-yasg</a> generates <a href="https://openapis.org/">OpenAPI</a> documents suitable for code generation - nested schemas,
|
||||
named models, response bodies, enum/pattern/min/max validators, form parameters, etc.</p>
|
||||
<h2 id="drf-spectacular-sane-and-flexible-openapi-30-schema-generation-for-django-rest-framework"><a class="toclink" href="#drf-spectacular-sane-and-flexible-openapi-30-schema-generation-for-django-rest-framework">drf-spectacular - Sane and flexible OpenAPI 3.0 schema generation for Django REST framework</a></h2>
|
||||
<p><a href="https://github.com/tfranzel/drf-spectacular/">drf-spectacular</a> is a <a href="https://openapis.org/">OpenAPI 3</a> schema generation tool with explicit focus on extensibility,
|
||||
customizability and client generation. It's usage patterns are very similar to <a href="https://github.com/axnsan12/drf-yasg/">drf-yasg</a>.</p>
|
||||
|
||||
|
||||
</div> <!--/span-->
|
||||
|
|
195
css/base.css
|
@ -1,5 +1,9 @@
|
|||
body {
|
||||
padding-top: 70px;
|
||||
html {
|
||||
/* csslint ignore:start */
|
||||
/* The nav header is 3.5rem high, plus 20px for the margin-top of the
|
||||
main container. */
|
||||
scroll-padding-top: calc(3.5rem + 20px);
|
||||
/* csslint ignore:end */
|
||||
}
|
||||
|
||||
/* Replacement for `body { background-attachment: fixed; }`, which has
|
||||
|
@ -18,20 +22,15 @@ body::before {
|
|||
}
|
||||
|
||||
body > .container {
|
||||
margin-top: 20px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
ul.nav .main {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.col-md-3 {
|
||||
padding-left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.col-md-9 {
|
||||
padding-bottom: 100px;
|
||||
.navbar.fixed-top { /* csslint allow: adjoining-classes */
|
||||
/* csslint ignore:start */
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
/* csslint ignore:end */
|
||||
}
|
||||
|
||||
.source-links {
|
||||
|
@ -49,19 +48,6 @@ ul.nav .main {
|
|||
margin: 20px auto 30px auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* The code below adds some padding to the top of the current anchor target so
|
||||
* that, when navigating to it, the header isn't hidden by the navbar at the
|
||||
* top.
|
||||
*/
|
||||
:target::before {
|
||||
content: "";
|
||||
display: block;
|
||||
margin-top: -75px;
|
||||
height: 75px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #444;
|
||||
font-weight: 400;
|
||||
|
@ -99,11 +85,12 @@ code {
|
|||
}
|
||||
|
||||
pre code {
|
||||
display: block;
|
||||
background: transparent;
|
||||
border: none;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
font-family: monospace,serif;
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
@ -143,22 +130,45 @@ footer {
|
|||
* sections of docs content.
|
||||
*/
|
||||
|
||||
/* By default it's not affixed in mobile views, so undo that */
|
||||
.bs-sidebar.affix { /* csslint allow: adjoining-classes */
|
||||
position: static;
|
||||
/* csslint ignore:start */
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
/* csslint ignore:end */
|
||||
/* The nav header is 3.5rem high, plus 20px for the margin-top of the
|
||||
main container. */
|
||||
top: calc(3.5rem + 20px);
|
||||
}
|
||||
|
||||
.bs-sidebar.well { /* csslint allow: adjoining-classes */
|
||||
.bs-sidebar.card { /* csslint allow: adjoining-classes */
|
||||
padding: 0;
|
||||
max-height: 90%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Toggle (vertically flip) sidebar collapse icon */
|
||||
.bs-sidebar .navbar-toggler span {
|
||||
-moz-transform: scale(1, -1);
|
||||
-webkit-transform: scale(1, -1);
|
||||
-o-transform: scale(1, -1);
|
||||
-ms-transform: scale(1, -1);
|
||||
transform: scale(1, -1);
|
||||
}
|
||||
|
||||
.bs-sidebar .navbar-toggler.collapsed span { /* csslint allow: adjoining-classes */
|
||||
-moz-transform: scale(1, 1);
|
||||
-webkit-transform: scale(1, 1);
|
||||
-o-transform: scale(1, 1);
|
||||
-ms-transform: scale(1, 1);
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
|
||||
/* First level of nav */
|
||||
.bs-sidenav {
|
||||
.bs-sidebar > .navbar-collapse > .nav {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* All levels of nav */
|
||||
|
@ -172,62 +182,24 @@ footer {
|
|||
text-decoration: none;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.bs-sidebar .nav > .active > a,
|
||||
.bs-sidebar .nav > .active:hover > a,
|
||||
.bs-sidebar .nav > .active:focus > a {
|
||||
.bs-sidebar .nav > li > a.active,
|
||||
.bs-sidebar .nav > li > a.active:hover,
|
||||
.bs-sidebar .nav > li > a.active:focus {
|
||||
font-weight: bold;
|
||||
background-color: transparent;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
|
||||
/* Nav: second level (shown on .active) */
|
||||
.bs-sidebar .nav .nav {
|
||||
display: none; /* Hide by default, but at >768px, show it */
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.bs-sidebar .nav .nav > li > a {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
padding-left: 30px;
|
||||
font-size: 90%;
|
||||
.bs-sidebar .nav .nav .nav {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
/* Show and affix the side nav when space allows it */
|
||||
@media (min-width: 992px) {
|
||||
/* Workaround a Safari bug when zooming to < 100%
|
||||
https://github.com/mkdocs/mkdocs/issues/1050 */
|
||||
.col-md-9 {
|
||||
box-sizing: border-box; /* csslint allow: box-sizing */
|
||||
padding-left: 25%;
|
||||
width: 100%;
|
||||
}
|
||||
.bs-sidebar .nav > .active > ul {
|
||||
display: block;
|
||||
}
|
||||
/* Widen the fixed sidebar */
|
||||
.bs-sidebar.affix, /* csslint allow: adjoining-classes */
|
||||
.bs-sidebar.affix-bottom { /* csslint allow: adjoining-classes */
|
||||
width: 213px;
|
||||
}
|
||||
.bs-sidebar.affix { /* csslint allow: adjoining-classes */
|
||||
position: fixed; /* Undo the static from mobile first approach */
|
||||
top: 80px;
|
||||
}
|
||||
.bs-sidebar.affix-bottom { /* csslint allow: adjoining-classes */
|
||||
position: absolute; /* Undo the static from mobile first approach */
|
||||
}
|
||||
.bs-sidebar.affix-bottom .bs-sidenav, /* csslint allow: adjoining-classes */
|
||||
.bs-sidebar.affix .bs-sidenav { /* csslint allow: adjoining-classes */
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.bs-sidebar .nav > li > a {
|
||||
font-weight: bold;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
/* Widen the fixed sidebar again */
|
||||
.bs-sidebar.affix-bottom, /* csslint allow: adjoining-classes */
|
||||
.bs-sidebar.affix { /* csslint allow: adjoining-classes */
|
||||
width: 263px;
|
||||
}
|
||||
|
||||
.bs-sidebar .nav .nav > li > a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.headerlink {
|
||||
|
@ -274,26 +246,25 @@ h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink, h4:hover .head
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.dropdown-submenu {
|
||||
position: relative;
|
||||
@media (max-width: 991.98px) {
|
||||
.navbar-collapse.show { /* csslint allow: adjoining-classes */
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 3.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-submenu>.dropdown-menu {
|
||||
top: 0;
|
||||
left: 100%;
|
||||
margin-top: -6px;
|
||||
margin-left: -1px;
|
||||
-webkit-border-radius: 0 6px 6px 6px;
|
||||
-moz-border-radius: 0 6px 6px;
|
||||
border-radius: 0 6px 6px 6px;
|
||||
.dropdown-item.open { /* csslint allow: adjoining-classes */
|
||||
color: #fff;
|
||||
background-color: #2FA4E7;
|
||||
}
|
||||
|
||||
.dropdown-submenu:hover>.dropdown-menu {
|
||||
display: block;
|
||||
.dropdown-submenu > .dropdown-menu {
|
||||
margin: 0 0 0 1.5rem;
|
||||
padding: 0;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.dropdown-submenu>a:after {
|
||||
.dropdown-submenu > a::after {
|
||||
display: block;
|
||||
content: " ";
|
||||
float: right;
|
||||
|
@ -307,18 +278,36 @@ h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink, h4:hover .head
|
|||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.dropdown-submenu:hover>a:after {
|
||||
.dropdown-submenu:hover > a::after {
|
||||
border-left-color: #fff;
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left { /* csslint allow: adjoining-classes */
|
||||
float: none;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.dropdown-menu {
|
||||
overflow-y: auto;
|
||||
max-height: calc(100vh - 3.5rem);
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left>.dropdown-menu { /* csslint allow: adjoining-classes */
|
||||
left: -100%;
|
||||
margin-left: 10px;
|
||||
-webkit-border-radius: 6px 0 6px 6px;
|
||||
-moz-border-radius: 6px 0 6px 6px;
|
||||
border-radius: 6px 0 6px 6px;
|
||||
.dropdown-submenu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-submenu > .dropdown-menu {
|
||||
/* csslint ignore:start */
|
||||
position: fixed !important;
|
||||
/* csslint ignore:end */
|
||||
margin-top: -9px;
|
||||
margin-left: -2px;
|
||||
border-width: 1px;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left { /* csslint allow: adjoining-classes */
|
||||
float: none;
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left > .dropdown-menu { /* csslint allow: adjoining-classes */
|
||||
left: -100%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
|
1
css/bootstrap-custom.min.css
vendored
12
css/bootstrap.min.css
vendored
Normal file
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
12
index.html
|
@ -293,6 +293,10 @@
|
|||
<a href="community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -549,8 +553,8 @@ continued development by <strong><a href="community/funding/">signing up for a p
|
|||
<h2 id="requirements"><a class="toclink" href="#requirements">Requirements</a></h2>
|
||||
<p>REST framework requires the following:</p>
|
||||
<ul>
|
||||
<li>Python (3.5, 3.6, 3.7, 3.8)</li>
|
||||
<li>Django (2.2, 3.0)</li>
|
||||
<li>Python (3.5, 3.6, 3.7, 3.8, 3.9)</li>
|
||||
<li>Django (2.2, 3.0, 3.1)</li>
|
||||
</ul>
|
||||
<p>We <strong>highly recommend</strong> and only officially support the latest patch release of
|
||||
each Python and Django series.</p>
|
||||
|
@ -580,7 +584,7 @@ pip install django-filter # Filtering support
|
|||
<p>If you're intending to use the browsable API you'll probably also want to add REST framework's login and logout views. Add the following to your root <code>urls.py</code> file.</p>
|
||||
<pre><code>urlpatterns = [
|
||||
...
|
||||
url(r'^api-auth/', include('rest_framework.urls'))
|
||||
path('api-auth/', include('rest_framework.urls'))
|
||||
]
|
||||
</code></pre>
|
||||
<p>Note that the URL path can be whatever you want.</p>
|
||||
|
@ -723,4 +727,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>
|
|||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
317
js/base.js
|
@ -1,38 +1,46 @@
|
|||
function getSearchTerm()
|
||||
{
|
||||
function getSearchTerm() {
|
||||
var sPageURL = window.location.search.substring(1);
|
||||
var sURLVariables = sPageURL.split('&');
|
||||
for (var i = 0; i < sURLVariables.length; i++)
|
||||
{
|
||||
for (var i = 0; i < sURLVariables.length; i++) {
|
||||
var sParameterName = sURLVariables[i].split('=');
|
||||
if (sParameterName[0] == 'q')
|
||||
{
|
||||
if (sParameterName[0] == 'q') {
|
||||
return sParameterName[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyTopPadding() {
|
||||
// Update various absolute positions to match where the main container
|
||||
// starts. This is necessary for handling multi-line nav headers, since
|
||||
// that pushes the main container down.
|
||||
var offset = $('body > .container').offset();
|
||||
$('html').css('scroll-padding-top', offset.top + 'px');
|
||||
$('.bs-sidebar.affix').css('top', offset.top + 'px');
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
applyTopPadding();
|
||||
|
||||
var search_term = getSearchTerm(),
|
||||
$search_modal = $('#mkdocs_search_modal'),
|
||||
$keyboard_modal = $('#mkdocs_keyboard_modal');
|
||||
|
||||
if(search_term){
|
||||
if (search_term) {
|
||||
$search_modal.modal();
|
||||
}
|
||||
|
||||
// make sure search input gets autofocus everytime modal opens.
|
||||
$search_modal.on('shown.bs.modal', function () {
|
||||
$search_modal.on('shown.bs.modal', function() {
|
||||
$search_modal.find('#mkdocs-search-query').focus();
|
||||
});
|
||||
|
||||
// Close search modal when result is selected
|
||||
// The links get added later so listen to parent
|
||||
$('#mkdocs-search-results').click(function(e) {
|
||||
if ($(e.target).is('a')) {
|
||||
$search_modal.modal('hide');
|
||||
}
|
||||
if ($(e.target).is('a')) {
|
||||
$search_modal.modal('hide');
|
||||
}
|
||||
});
|
||||
|
||||
// Populate keyboard modal with proper Keys
|
||||
|
@ -48,10 +56,10 @@ $(document).ready(function() {
|
|||
var page;
|
||||
switch (key) {
|
||||
case shortcuts.next:
|
||||
page = $('[role="navigation"] a:contains(Next):first').prop('href');
|
||||
page = $('.navbar a[rel="next"]:first').prop('href');
|
||||
break;
|
||||
case shortcuts.previous:
|
||||
page = $('[role="navigation"] a:contains(Previous):first').prop('href');
|
||||
page = $('.navbar a[rel="prev"]:first').prop('href');
|
||||
break;
|
||||
case shortcuts.search:
|
||||
e.preventDefault();
|
||||
|
@ -86,8 +94,67 @@ $(document).ready(function() {
|
|||
}, 50);
|
||||
});
|
||||
|
||||
function showInnerDropdown(item) {
|
||||
var popup = $(item).next('.dropdown-menu');
|
||||
popup.addClass('show');
|
||||
$(item).addClass('open');
|
||||
|
||||
// First, close any sibling dropdowns.
|
||||
var container = $(item).parent().parent();
|
||||
container.find('> .dropdown-submenu > a').each(function(i, el) {
|
||||
if (el !== item) {
|
||||
hideInnerDropdown(el);
|
||||
}
|
||||
});
|
||||
|
||||
var popupMargin = 10;
|
||||
var maxBottom = $(window).height() - popupMargin;
|
||||
var bounds = item.getBoundingClientRect();
|
||||
|
||||
popup.css('left', bounds.right + 'px');
|
||||
if (bounds.top + popup.height() > maxBottom &&
|
||||
bounds.top > $(window).height() / 2) {
|
||||
popup.css({
|
||||
'top': (bounds.bottom - popup.height()) + 'px',
|
||||
'max-height': (bounds.bottom - popupMargin) + 'px',
|
||||
});
|
||||
} else {
|
||||
popup.css({
|
||||
'top': bounds.top + 'px',
|
||||
'max-height': (maxBottom - bounds.top) + 'px',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hideInnerDropdown(item) {
|
||||
var popup = $(item).next('.dropdown-menu');
|
||||
popup.removeClass('show');
|
||||
$(item).removeClass('open');
|
||||
|
||||
popup.scrollTop(0);
|
||||
popup.find('.dropdown-menu').scrollTop(0).removeClass('show');
|
||||
popup.find('.dropdown-submenu > a').removeClass('open');
|
||||
}
|
||||
|
||||
$('.dropdown-submenu > a').on('click', function(e) {
|
||||
if ($(this).next('.dropdown-menu').hasClass('show')) {
|
||||
hideInnerDropdown(this);
|
||||
} else {
|
||||
showInnerDropdown(this);
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$('.dropdown-menu').parent().on('hide.bs.dropdown', function(e) {
|
||||
$(this).find('.dropdown-menu').scrollTop(0);
|
||||
$(this).find('.dropdown-submenu > a').removeClass('open');
|
||||
$(this).find('.dropdown-menu .dropdown-menu').removeClass('show');
|
||||
});
|
||||
});
|
||||
|
||||
$(window).on('resize', applyTopPadding);
|
||||
|
||||
$('body').scrollspy({
|
||||
target: '.bs-sidebar',
|
||||
|
@ -100,117 +167,117 @@ $("li.disabled a").click(function() {
|
|||
});
|
||||
|
||||
// See https://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
|
||||
// We only list common keys below. Obscure keys are omited and their use is discouraged.
|
||||
// We only list common keys below. Obscure keys are omitted and their use is discouraged.
|
||||
var keyCodes = {
|
||||
8: 'backspace',
|
||||
9: 'tab',
|
||||
13: 'enter',
|
||||
16: 'shift',
|
||||
17: 'ctrl',
|
||||
18: 'alt',
|
||||
19: 'pause/break',
|
||||
20: 'caps lock',
|
||||
27: 'escape',
|
||||
32: 'spacebar',
|
||||
33: 'page up',
|
||||
34: 'page down',
|
||||
35: 'end',
|
||||
36: 'home',
|
||||
37: '←',
|
||||
38: '↑',
|
||||
39: '→',
|
||||
40: '↓',
|
||||
45: 'insert',
|
||||
46: 'delete',
|
||||
48: '0',
|
||||
49: '1',
|
||||
50: '2',
|
||||
51: '3',
|
||||
52: '4',
|
||||
53: '5',
|
||||
54: '6',
|
||||
55: '7',
|
||||
56: '8',
|
||||
57: '9',
|
||||
65: 'a',
|
||||
66: 'b',
|
||||
67: 'c',
|
||||
68: 'd',
|
||||
69: 'e',
|
||||
70: 'f',
|
||||
71: 'g',
|
||||
72: 'h',
|
||||
73: 'i',
|
||||
74: 'j',
|
||||
75: 'k',
|
||||
76: 'l',
|
||||
77: 'm',
|
||||
78: 'n',
|
||||
79: 'o',
|
||||
80: 'p',
|
||||
81: 'q',
|
||||
82: 'r',
|
||||
83: 's',
|
||||
84: 't',
|
||||
85: 'u',
|
||||
86: 'v',
|
||||
87: 'w',
|
||||
88: 'x',
|
||||
89: 'y',
|
||||
90: 'z',
|
||||
91: 'Left Windows Key / Left ⌘',
|
||||
92: 'Right Windows Key',
|
||||
93: 'Windows Menu / Right ⌘',
|
||||
96: 'numpad 0',
|
||||
97: 'numpad 1',
|
||||
98: 'numpad 2',
|
||||
99: 'numpad 3',
|
||||
100: 'numpad 4',
|
||||
101: 'numpad 5',
|
||||
102: 'numpad 6',
|
||||
103: 'numpad 7',
|
||||
104: 'numpad 8',
|
||||
105: 'numpad 9',
|
||||
106: 'multiply',
|
||||
107: 'add',
|
||||
109: 'subtract',
|
||||
110: 'decimal point',
|
||||
111: 'divide',
|
||||
112: 'f1',
|
||||
113: 'f2',
|
||||
114: 'f3',
|
||||
115: 'f4',
|
||||
116: 'f5',
|
||||
117: 'f6',
|
||||
118: 'f7',
|
||||
119: 'f8',
|
||||
120: 'f9',
|
||||
121: 'f10',
|
||||
122: 'f11',
|
||||
123: 'f12',
|
||||
124: 'f13',
|
||||
125: 'f14',
|
||||
126: 'f15',
|
||||
127: 'f16',
|
||||
128: 'f17',
|
||||
129: 'f18',
|
||||
130: 'f19',
|
||||
131: 'f20',
|
||||
132: 'f21',
|
||||
133: 'f22',
|
||||
134: 'f23',
|
||||
135: 'f24',
|
||||
144: 'num lock',
|
||||
145: 'scroll lock',
|
||||
186: ';',
|
||||
187: '=',
|
||||
188: ',',
|
||||
189: '‐',
|
||||
190: '.',
|
||||
191: '?',
|
||||
192: '`',
|
||||
219: '[',
|
||||
220: '\',
|
||||
221: ']',
|
||||
222: ''',
|
||||
8: 'backspace',
|
||||
9: 'tab',
|
||||
13: 'enter',
|
||||
16: 'shift',
|
||||
17: 'ctrl',
|
||||
18: 'alt',
|
||||
19: 'pause/break',
|
||||
20: 'caps lock',
|
||||
27: 'escape',
|
||||
32: 'spacebar',
|
||||
33: 'page up',
|
||||
34: 'page down',
|
||||
35: 'end',
|
||||
36: 'home',
|
||||
37: '←',
|
||||
38: '↑',
|
||||
39: '→',
|
||||
40: '↓',
|
||||
45: 'insert',
|
||||
46: 'delete',
|
||||
48: '0',
|
||||
49: '1',
|
||||
50: '2',
|
||||
51: '3',
|
||||
52: '4',
|
||||
53: '5',
|
||||
54: '6',
|
||||
55: '7',
|
||||
56: '8',
|
||||
57: '9',
|
||||
65: 'a',
|
||||
66: 'b',
|
||||
67: 'c',
|
||||
68: 'd',
|
||||
69: 'e',
|
||||
70: 'f',
|
||||
71: 'g',
|
||||
72: 'h',
|
||||
73: 'i',
|
||||
74: 'j',
|
||||
75: 'k',
|
||||
76: 'l',
|
||||
77: 'm',
|
||||
78: 'n',
|
||||
79: 'o',
|
||||
80: 'p',
|
||||
81: 'q',
|
||||
82: 'r',
|
||||
83: 's',
|
||||
84: 't',
|
||||
85: 'u',
|
||||
86: 'v',
|
||||
87: 'w',
|
||||
88: 'x',
|
||||
89: 'y',
|
||||
90: 'z',
|
||||
91: 'Left Windows Key / Left ⌘',
|
||||
92: 'Right Windows Key',
|
||||
93: 'Windows Menu / Right ⌘',
|
||||
96: 'numpad 0',
|
||||
97: 'numpad 1',
|
||||
98: 'numpad 2',
|
||||
99: 'numpad 3',
|
||||
100: 'numpad 4',
|
||||
101: 'numpad 5',
|
||||
102: 'numpad 6',
|
||||
103: 'numpad 7',
|
||||
104: 'numpad 8',
|
||||
105: 'numpad 9',
|
||||
106: 'multiply',
|
||||
107: 'add',
|
||||
109: 'subtract',
|
||||
110: 'decimal point',
|
||||
111: 'divide',
|
||||
112: 'f1',
|
||||
113: 'f2',
|
||||
114: 'f3',
|
||||
115: 'f4',
|
||||
116: 'f5',
|
||||
117: 'f6',
|
||||
118: 'f7',
|
||||
119: 'f8',
|
||||
120: 'f9',
|
||||
121: 'f10',
|
||||
122: 'f11',
|
||||
123: 'f12',
|
||||
124: 'f13',
|
||||
125: 'f14',
|
||||
126: 'f15',
|
||||
127: 'f16',
|
||||
128: 'f17',
|
||||
129: 'f18',
|
||||
130: 'f19',
|
||||
131: 'f20',
|
||||
132: 'f21',
|
||||
133: 'f22',
|
||||
134: 'f23',
|
||||
135: 'f24',
|
||||
144: 'num lock',
|
||||
145: 'scroll lock',
|
||||
186: ';',
|
||||
187: '=',
|
||||
188: ',',
|
||||
189: '‐',
|
||||
190: '.',
|
||||
191: '?',
|
||||
192: '`',
|
||||
219: '[',
|
||||
220: '\',
|
||||
221: ']',
|
||||
222: ''',
|
||||
};
|
||||
|
|
7
js/bootstrap-3.0.3.min.js
vendored
7
js/bootstrap.min.js
vendored
Normal file
779
search/lunr.js
329
sitemap.xml
|
@ -1,328 +1,267 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url>
|
||||
<loc>https://www.django-rest-framework.org/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/tutorial/quickstart/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/tutorial/1-serialization/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/tutorial/2-requests-and-responses/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/tutorial/3-class-based-views/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/requests/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/responses/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/views/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/generic-views/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/viewsets/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/routers/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/parsers/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/renderers/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/serializers/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/fields/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/relations/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/validators/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/authentication/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/permissions/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/caching/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/throttling/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/filtering/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/pagination/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/versioning/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/content-negotiation/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/metadata/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/schemas/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/format-suffixes/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/reverse/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/exceptions/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/status-codes/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/testing/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/api-guide/settings/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/documenting-your-api/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/api-clients/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/internationalization/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/ajax-csrf-cors/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/html-and-forms/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/browser-enhancements/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/browsable-api/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/topics/rest-hypermedia-hateoas/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/tutorials-and-resources/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/third-party-packages/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/contributing/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/project-management/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/release-notes/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.12-announcement/</loc>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.11-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.10-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.9-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.8-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.7-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.6-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.5-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.4-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.3-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.2-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.1-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/3.0-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/kickstarter-announcement/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/mozilla-grant/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/funding/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
</url><url>
|
||||
<loc>https://www.django-rest-framework.org/community/jobs/</loc>
|
||||
<lastmod>2020-07-29</lastmod>
|
||||
<lastmod>2020-09-28</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
</urlset>
|
BIN
sitemap.xml.gz
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -793,7 +797,7 @@ that modify the outgoing requests.</p>
|
|||
|
||||
urlpatterns = [
|
||||
...
|
||||
url(r'^docs/', include_docs_urls(title='My API service'), name='api-docs'),
|
||||
path('docs/', include_docs_urls(title='My API service'), name='api-docs'),
|
||||
]
|
||||
</code></pre>
|
||||
<p>Once the API documentation URLs are installed, you'll be able to include both the required JavaScript resources. Note that the ordering of these two lines is important, as the schema loading requires CoreAPI to already be installed.</p>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -553,6 +557,13 @@ response bodies, enum/pattern/min/max validators, form parameters, etc. - and to
|
|||
generation tools like <code>swagger-codegen</code>.</p>
|
||||
<p>This also translates into a very useful interactive documentation viewer in the form of <code>swagger-ui</code>:</p>
|
||||
<p><img alt="Screenshot - drf-yasg" src="../../img/drf-yasg.png" /></p>
|
||||
<h4 id="drf-spectacular-sane-and-flexible-openapi-30-schema-generation-for-django-rest-framework"><a class="toclink" href="#drf-spectacular-sane-and-flexible-openapi-30-schema-generation-for-django-rest-framework">drf-spectacular - Sane and flexible OpenAPI 3.0 schema generation for Django REST framework</a></h4>
|
||||
<p><a href="https://github.com/tfranzel/drf-spectacular/">drf-spectacular</a> is a <a href="https://openapis.org/">OpenAPI 3</a> schema generation tool with explicit focus on extensibility,
|
||||
customizability and client generation. Usage patterns are very similar to <a href="https://github.com/axnsan12/drf-yasg/">drf-yasg</a>.</p>
|
||||
<p>It aims to extract as much schema information as possible, while providing decorators and extensions for easy
|
||||
customization. There is explicit support for <a href="https://swagger.io/">swagger-codegen</a>, <a href="https://swagger.io/tools/swagger-ui/">SwaggerUI</a> and <a href="https://github.com/Rebilly/ReDoc">Redoc</a>,
|
||||
i18n, versioning, authentication, polymorphism (dynamic requests and responses), query/path/header parameters,
|
||||
documentation and more. Several popular plugins for DRF are supported out-of-the-box as well.</p>
|
||||
<hr />
|
||||
<h2 id="self-describing-apis"><a class="toclink" href="#self-describing-apis">Self describing APIs</a></h2>
|
||||
<p>The browsable API that REST framework provides makes it possible for your API to be entirely self describing. The documentation for each API endpoint can be provided simply by visiting the URL in your browser.</p>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -435,7 +439,7 @@
|
|||
<h1 id="rest-hypermedia-hateoas"><a class="toclink" href="#rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</a></h1>
|
||||
<blockquote>
|
||||
<p>You keep using that word "REST". I do not think it means what you think it means.</p>
|
||||
<p>— Mike Amundsen, <a href="https://vimeo.com/channels/restfest/page:2">REST fest 2012 keynote</a>.</p>
|
||||
<p>— Mike Amundsen, <a href="https://vimeo.com/channels/restfest/49503453">REST fest 2012 keynote</a>.</p>
|
||||
</blockquote>
|
||||
<p>First off, the disclaimer. The name "Django REST framework" was decided back in early 2011 and was chosen simply to sure the project would be easily found by developers. Throughout the documentation we try to use the more simple and technically correct terminology of "Web APIs".</p>
|
||||
<p>If you are serious about designing a Hypermedia API, you should look to resources outside of this documentation to help inform your design choices.</p>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -432,7 +436,7 @@
|
|||
<p>Although flat data structures serve to properly delineate between the individual entities in your service, there are cases where it may be more appropriate or convenient to use nested data structures.</p>
|
||||
<p>Nested data structures are easy enough to work with if they're read-only - simply nest your serializer classes and you're good to go. However, there are a few more subtleties to using writable nested serializers, due to the dependencies between the various model instances, and the need to save or delete multiple instances in a single action.</p>
|
||||
<h2 id="one-to-many-data-structures"><a class="toclink" href="#one-to-many-data-structures">One-to-many data structures</a></h2>
|
||||
<p><em>Example of a <strong>read-only</strong> nested serializer. Nothing complex to worry about here.</em></p>
|
||||
<p><em>Example of a </em><em>read-only</em><em> nested serializer. Nothing complex to worry about here.</em></p>
|
||||
<pre><code>class ToDoItemSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ToDoItem
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -561,7 +565,7 @@ path('users/<int:pk>/', views.UserDetail.as_view()),
|
|||
<p>If you open a browser and navigate to the browsable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user.</p>
|
||||
<p>We can add a login view for use with the browsable API, by editing the URLconf in our project-level <code>urls.py</code> file.</p>
|
||||
<p>Add the following import at the top of the file:</p>
|
||||
<pre><code>from django.conf.urls import include
|
||||
<pre><code>from django.urls import path, include
|
||||
</code></pre>
|
||||
<p>And, at the end of the file, add a pattern to include the login and logout views for the browsable API.</p>
|
||||
<pre><code>urlpatterns += [
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
|
|
@ -293,6 +293,10 @@
|
|||
<a href="../../community/release-notes/">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.12-announcement/">3.12 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../community/3.11-announcement/">3.11 Announcement</a>
|
||||
</li>
|
||||
|
@ -599,7 +603,7 @@ urlpatterns = [
|
|||
},
|
||||
{
|
||||
"email": "tom@example.com",
|
||||
"groups": [ ],
|
||||
"groups": [],
|
||||
"url": "http://127.0.0.1:8000/users/2/",
|
||||
"username": "tom"
|
||||
}
|
||||
|
@ -624,7 +628,7 @@ HTTP/1.1 200 OK
|
|||
},
|
||||
{
|
||||
"email": "tom@example.com",
|
||||
"groups": [ ],
|
||||
"groups": [],
|
||||
"url": "http://127.0.0.1:8000/users/2/",
|
||||
"username": "tom"
|
||||
}
|
||||
|
|