1. 什么是API?
简单看一下百科的解释:
API之主要目的是提供应用程序与开发人员以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。提供API所定义的功能的软件称作此API的实现。API是一种接口,故而是一种抽象。 应用程序接口(英语:ApplicationProgrammingInterface,简称:API),又称为应用编程接口,就是软件系统不同组成部分衔接的约定。
简单来说,我们写程序是为了帮用户完成某件事,用户不需要知道我们是怎么完成的。对于用户来说,只需发个指令,譬如,“我想导航到萧山”,那么程序能把路线告诉用户即可。API是什么呢,就是接受用户指令,并返回程序结果的一个工具。
2. 安装djangorestframework包
作为网络开发程序员,我们要为用户提供API 并告诉用户如何使用我们的软件。用于开发API的工具有很多,在Django项目中,一般使用djangorestframework包来开发API。
djangorestframework包直接使用pip安装即可
1 pip install djangorestframework
3. 建立Django项目
在本文中,我们通过建立一个电影网站,让用户 获取、修改以及增加新的电影信息,以熟悉Django API的构建。
可以参考[[基本Django项目构建]]一文建立起项目,简单列举一下相关命令。
1 2 3 4 5 django-admin startproject movie_api cd movie_api python manage.py startapp movie python manage.py migrate python manage.py runserver
这样就可以跑起来一个空项目了。
因为本文只关注API的构建,这里只建立一个数据模型,其他的网页浏览视图、模板就不做了。
3.1 建立Model
在movie/models.py中建立电影数据类,
1 2 3 4 5 6 7 8 9 from django.db import modelsclass Movie (models.Model): name = models.CharField(max_length=200 ) year = models.IntegerField() def __str__ (self ): return f'{self.name} ({self.year} )'
对数据模型更改后,要进行迁移
1 2 python manage.py makemigrations python manage.py migrate
使用python manage.py shell进行项目的shell添加一些数据
1 2 3 4 5 6 7 8 9 10 11 12 13 >>> from movie.models import Movie>>> Movie.objects.create(name="The Shawshank Redemption" , year=1994 )<Movie: The Shawshank Redemption (1994 )> >>> Movie.objects.create(name="The Godfather" , year=1972 )<Movie: The Godfather (1972 )> >>> Movie.objects.create(name="The Dark Knight" , year=2008 )<Movie: The Dark Knight (2008 )> >>> Movie.objects.create(name='The Godfather: Part II' , year=1974 )<Movie: The Godfather: Part II (1974 )> >>> Movie.objects.create(name='12 Angry Men' , year=1957 )<Movie: 12 Angry Men (1957 )> >>> Movie.objects.all ()<QuerySet [<Movie: The Shawshank Redemption (1994 )>, <Movie: The Godfather (1972 )>, <Movie: The Dark Knight (2008 )>, <Movie: The Godfather: Part II (1974 )>, <Movie: 12 Angry Men (1957 )>]>
4. 构建API
首先在movie_api/settings.py文件找到INSTALLED_APPS, 注册rest_framework,现在这个列表应该如下,
1 2 3 4 5 INSTALLED_APPS = [ ... 'movie' , 'rest_framework' , ]
为了避免与网站基本内容混淆,可以项目根目录下建立一个专门的api文件夹,并在其中建立一个空的__init__.py文件,表明这是一个包。
4.1 建立序列化器
我们把变量从内存中变成可存储或传输的过程称之为序列化。——廖雪峰
也就是说,从数据库中把数据读到我们的Model类型的变量中后,还要经过序列化,才能顺利传输到客户端(浏览器),供用户浏览使用。
在api文件夹下建立serializers.py文件,内容如下
1 2 3 4 5 6 7 from rest_framework import serializersfrom movie.models import Movieclass MovieSerializer (serializers.ModelSerializer): class Meta : model = Movie fields= '__all__'
这里建立了一个Movie专用的序列化器,其中序列化的数据包括所有字段。
4.2 建立视图并绑定URL
4.2.1 获取所有电影
在api文件夹下建立views.py文件
1 2 3 4 5 6 7 8 9 10 11 from rest_framework.decorators import api_viewfrom movie.models import Moviefrom .serializers import MovieSerializerfrom rest_framework.response import Response@api_view(['GET' ] ) def get_movies (request ): movies = Movie.objects.all () serializer = MovieSerializer(movies, many=True ) return Response(serializer.data)
这里通过装饰器来设置请求方法,这里只是获取,用GET即可。
注意在一个普通的网站中,获取了电影列表后,应该传输给前端的模板,以供渲染,但在API中,我们进行序列化,以供传输。
然后绑定url,在api文件夹下建立urls.py文件,
1 2 3 4 5 6 from django.urls import pathfrom . import viewsurlpatterns = [ path('' , views.get_movies, name='get_movies' ) ]
如文章[[基本Django项目构建]]中提到的,还没有被django项目所识别,因此,需要在movie_api/urls.py文件中进行引用,以让项目进行识别。
1 2 3 4 5 6 from django.urls import path, includeurlpatterns = [ path('admin/' , admin.site.urls), path('movies/' , include('api.urls' )), ]
这样,运行项目后,我们就可以通过网址http://127.0.0.1:8000/movies/ 访问电影列表api了,效果如下:
4.2.2 新增电影
新增电影条目可以保持与电影列表的网址相同,只需要在视图中增加一个POST请求方法即可。修改api/views.py中相关函数如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from rest_framework import status@api_view(['GET' , 'POST' ] ) def get_movies (request ): if request.method == 'GET' : movies = Movie.objects.all () serializer = MovieSerializer(movies, many=True ) return Response(serializer.data) elif request.method == 'POST' : serializer = MovieSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
要注意的是,一旦数据有变动,要使用is_valid进行数据的验证并使用save保存,这里包括类型、长度 等的验证。
再次访问网址http://127.0.0.1:8000/movies/ ,可以看到下方多出了一个输入框,以增加电影条目。
4.2.3 获取某个电影的信息
这里也是获取内容,与[[#4 2 1 获取所有电影]]类似,首先在api/views.py中添加视图函数,
1 2 3 4 5 @api_view(['PUT' ] ) def get_movie_detail (request, id ): movie = Movie.objects.get(pk=id ) serializer = MovieSerializer(movie) return Response(serializer.data)
然后在api/urls.py中绑定网址,
1 2 3 urlpatterns = [ path('<int:id>' , views.get_movie_detail, name='get_movie_detail' ), ]
即可通过http://127.0.0.1:8000/movies/1 访问id为1的电影信息了。
4.2.4 修改或删除某个电影的信息
修改或删除也是针对某个电影,所以网址与[[#4 2 3 获取某个电影的信息]]可以相同,不过请求方法需要设置为PUT和DELETE,修改相应的视图函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @api_view(['GET' , 'PUT' , 'DELETE' ] ) def get_movie_detail (request, id ): movie = Movie.objects.get(pk=id ) if request.method == 'GET' : serializer = MovieSerializer(movie) return Response(serializer.data) elif request.method == 'PUT' : serializer = MovieSerializer(movie, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) elif request.method == 'DELETE' : movie.delete() return Response(status=status.HTTP_204_NO_CONTENT)
这里增加了对请求方法PUT和DELETE的支持,在函数体中,针对不同的请求类型,有不同的处理。
修改后页面效果如下,可以进行内容的修改和条目的删除。
5. 回顾
简单回顾一下,在一个普通的网站项目基础上,首先建立了专门的API文件夹,在其中首先建立序列化器以进行数据转化传输,然后建立了各类视图,并通过不同请求方法进行数据的增、删、改、查(即CRUD操作)API的构建。
可以看到,API的视图函数与一般网站视图函数的主要区别在于,API的视图函数是从数据库获取数据后进行序列化再传输,而一般网站视图函数则是获取数据后传递给前端模板以供展示。