Currently, the relationships in our API are represented by a primary key. in this part of the tutorial, we will improve the cohesion and visibility of the API, rather than using the associated hyperlinks.
Create an endpoint for the root of our API
Now we have the endpoints of ' snippets ' and ' users ', but our API doesn't have an entry point. To create an entry point, we will use a regular function-based view and the adorner we described earlier @api_view
. in your snippets/views.py
add:
From rest_framework.decorators import api_viewfrom rest_framework.response import Responsefrom rest_framework.reverse Import Reverse@api_view ([' GET ']) def api_root (Request, Format=none): return Response ({ ' users ': Reverse (' User-list ', Request=request, Format=format), ' snippets ': reverse (' snippet-list ', Request=request, Format=format ) })
There are two things to be aware of here. First, we use the rest framework's reverse
functions to return fully qualified URLs, and secondly, the URL pattern is identified by a convenient name, which we will later snippets/urls.py中
declare.
Create an endpoint for highlighted snippets
Another obvious thing that remains missing from our Pastebin API is the code highlighting endpoints.
Unlike all other API endpoints, we do not want to use JSON, but just render the HTML presentation layer. The rest framework provides two kinds of HTML renderer styles, one that uses templates to resolve HTML rendering, and another that uses pre-rendered HTML. The second renderer is the one we want to use for this endpoint.
Another thing we need to consider when creating a code highlighting view is that there is no ready-made, generic view for us to use. Instead of returning an object instance, we return the properties of an object instance.
Instead of using a specific generic view, we use the base class to represent the instance and create our own .get()
methods. In your snippets/views.py
add :
From rest_framework import renderersfrom rest_framework.response import Responseclass snippethighlight (generics. Genericapiview): queryset = Snippet.objects.all () renderer_classes = (renderers. Statichtmlrenderer,) def get (self, request, *args, **kwargs): snippet = Self.get_object () return Response (snippet.highlighted)
As always, we need to add a new view in urlconf. We will add snippets/urls.py
a URL pattern to our new API root in:
URL (r ' ^$ ', views.api_root),
Then add a URL pattern for snippet highlights:
URL (r ' ^snippets/(? p<pk>[0-9]+)/highlight/$ ', views. Snippethighlight.as_view ()),
Hyperlinking our API
Dealing with the relationship between entities is one of the more challenging aspects of Web API design. We can choose a number of different ways to represent a relationship:
- Use a primary key.
- Use hyperlinks between entities.
- Use a unique identity field on the related entity.
- Uses the default string representation of the related entity.
- Nest related entities within the parent representation.
- Some other custom representations.
The rest framework supports all of these styles and can be applied to a forward or reverse relationship, or to a custom manager such as a generic foreign key.
In this case, we want to use a hyperlink style between entities. To do this, we will modify our serializer to extend HyperlinkedModelSerializer
instead of the ModelSerializer
existing ones.
HyperlinkedModelSerializer
With the ModelSerializer
following differences:
- The ID field is not included by default.
- It includes a use
HyperlinkedIdentityField的url字段
.
- The relationship
HyperlinkedRelatedField
is used instead of PrimaryKeyRelatedField
.
We can use hyperlinks to easily rewrite our existing serializer. In your snippets/serializers.py
add:
Class Snippetserializer (serializers. Hyperlinkedmodelserializer): owner = serializers. Readonlyfield (source= ' owner.username ') highlight = serializers. Hyperlinkedidentityfield (view_name= ' snippet-highlight ', format= ' HTML ') class Meta: model = Snippet Fields = (' URL ', ' id ', ' highlight ', ' owner ', ' title ', ' Code ', ' Linenos ', ' language ', ' style ') class Userserializer ( serializers. Hyperlinkedmodelserializer): snippets = serializers. Hyperlinkedrelatedfield (many=true, view_name= ' Snippet-detail ', read_only=true) class Meta: model = User Fields = (' URL ', ' id ', ' username ', ' snippets ')
Note that we have also added a new ‘highlight‘
field. This field has the same type as the URL field, except that it points to the ‘snippet-highlight‘
URL pattern instead of the ‘snippet-detail‘
URL pattern.
Because we include the URL of the format suffix, ‘.json‘
We also need to indicate on the highlight
field that any hyperlink that returns a format suffix should use a ‘.html‘
suffix.
Making sure our URL patterns is named
If we want to use the hyperlink type API, then we need to name the URL pattern. Let's take a look at the URL pattern we need to name.
- The source of our API is to refer to
‘user-list‘
and ‘snippet-list‘
.
- Our fragment serializer includes a referenced
‘snippet-highlight‘
field.
- Our user serializer includes a referenced
‘snippet-detail‘
field.
- Our fragment and user serializer includes
‘{model_name}-detail‘
the ' url ' field that will be referenced by default, in which case it will be ‘snippet-detail‘
and ‘user-detail‘
.
After adding all of these names to our urlconf, the final snippets/urls.py
file should look like this:
From django.conf.urls import URL, includefrom rest_framework.urlpatterns import format_suffix_patternsfrom Snippets Import views# API endpointsurlpatterns = format_suffix_patterns ([ url (R ' ^$ ', views.api_root), url (r ' ^ snippets/$ ', views . Snippetlist.as_view (), name= ' snippet-list '), url (r ' ^snippets/(? p<pk>[0-9]+)/$ ', views . Snippetdetail.as_view (), name= ' Snippet-detail '), url (r ' ^snippets/(? p<pk>[0-9]+)/highlight/$ ', views . Snippethighlight.as_view (), name= ' snippet-highlight '), url (r ' ^users/$ ', views . Userlist.as_view (), name= ' user-list '), url (r ' ^users/(? p<pk>[0-9]+)/$ ', views . Userdetail.as_view (), name= ' User-detail ')] # Login and logout views for the browsable apiurlpatterns + = [ URL ( R ' ^api-auth/', include (' Rest_framework.urls ', namespace= ' rest_framework ')),]
Add pagination
The list view of users and code snippets may return quite a few instances, so we want to make sure that the results are paged out and allow the API client to step through each individual page.
We can change the tutorial/settings.py
default list style to use pagination by slightly modifying our files. Add the following settings:
Rest_framework = { ' page_size ': 10}
Note that the settings in the REST framework are named a single dictionary setting, called "Rest_framework," which helps maintain a good separation from other project settings.
We can also customize the paging style if we need to, but in this case we will stick to the default.
API (v) Relationships & hyperlinked APIs