美文网首页python 学习日记
基于Django Rest框架实现API构建

基于Django Rest框架实现API构建

作者: 小黑天天快乐 | 来源:发表于2022-03-27 21:53 被阅读0次

    本文首发于知乎https://zhuanlan.zhihu.com/p/488232953,禁止转载。

    1. 什么是API?

    简单看一下百科的解释:

    API之主要目的是提供应用程序与开发人员以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。提供API所定义的功能的软件称作此API的实现。API是一种接口,故而是一种抽象。 应用程序接口(英语:ApplicationProgrammingInterface,简称:API),又称为应用编程接口,就是软件系统不同组成部分衔接的约定。

    简单来说,某程序员写好了一个软件,希望作为服务提供给其他人使用,但又不想给别人看源码(或者别人也不想看…)。那么他可以告诉别人,我这个软件有哪些功能, 则用户可以通过调用特定函数获取到所需的数据或执行某些操作,这就是API的作用啦。

    2. 安装djangorestframework包

    作为网络开发程序员,我们就是那个写软件的程序员,所以我们要为用户提供API 并告诉用户如何使用我们的软件。在Django项目中,一般使用djangorestframework包来开发API。

    djangorestframework包直接使用pip安装即可

    pip install djangorestframework
    

    3. 建立Django项目

    在本文中,我们通过建立一个电影网站,让用户 获取、修改以及增加新的电影信息,以熟悉Django API的构建。

    可以参考基本Django项目构建一文建立起项目,简单列举一下相关命令。

    django-admin startproject movie_api
    cd movie_api
    python manage.py startapp movie # 这里记得在配置文件中加入movie
    python manage.py migrate
    python manage.py runserver
    

    这样就可以跑起来一个空项目了。

    因为本文只关注API的构建,这里只建立一个数据模型,其他的网页浏览视图、模板就不做了。

    3.1 建立Model

    movie/models.py中建立电影数据类,

    from django.db import models
    
    # Create your models here.
    class Movie(models.Model):
        name = models.CharField(max_length=200)
        year = models.IntegerField()
    
        def __str__(self):
            return f'{self.name} ({self.year})'
    

    对数据模型更改后,要进行迁移

    python manage.py makemigrations
    python manage.py migrate
    

    使用python manage.py shell进行项目的shell添加一些数据

    >>> 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,现在这个列表应该如下,

    INSTALLED_APPS = [
        ... # 其他已有值
        'movie',
        'rest_framework',
    ]
    

    为了避免与网站基本内容混淆,可以项目根目录下建立一个专门的api文件夹,并在其中建立一个空的__init__.py文件,表明这是一个包。

    4.1 建立序列化器

    我们把变量从内存中变成可存储或传输的过程称之为序列化。——廖雪峰

    也就是说,从数据库中把数据读到我们的Model类型的变量中后,还要经过序列化,才能顺利传输到客户端(浏览器),供用户浏览使用。

    在api文件夹下建立serializers.py文件,内容如下

    from rest_framework import serializers
    from movie.models import Movie
    
    class MovieSerializer(serializers.ModelSerializer):
        class Meta:
            model = Movie
            fields= '__all__'
    

    这里建立了一个Movie专用的序列化器,其中序列化的数据包括所有字段。

    4.2 建立视图并绑定URL

    4.2.1 获取所有电影

    在api文件夹下建立views.py文件

    from rest_framework.decorators import api_view
    from movie.models import Movie
    from .serializers import MovieSerializer
    from 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文件,

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.get_movies, name='get_movies')
    ]
    

    如文章基本Django项目构建中提到的,还没有被django项目所识别,因此,需要在movie_api/urls.py文件中进行引用,以让项目进行识别。

    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('movies/', include('api.urls')),
    ]
    

    这样,运行项目后,我们就可以通过网址http://127.0.0.1:8000/movies/访问电影列表api了,效果如下:

    电影列表API.png

    4.2.2 新增电影

    新增电影条目可以保持与电影列表的网址相同,只需要在视图中增加一个POST请求方法即可。修改api/views.py中相关函数如下,

    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中添加视图函数,

    @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中绑定网址,

    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,修改相应的视图函数如下:

    @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的支持,在函数体中,针对不同的请求类型,有不同的处理。

    修改后页面效果如下,可以进行内容的修改和条目的删除。


    某个电影信息.png

    5. 回顾

    简单回顾一下,在一个普通的网站项目基础上,首先建立了专门的API文件夹,在其中首先建立序列化器以进行数据转化传输,然后建立了各类视图,并通过不同请求方法进行数据的增、删、改、查(即CRUD操作)API的构建。

    可以看到,API的视图函数与一般网站视图函数的主要区别在于,API的视图函数是从数据库获取数据后进行序列化再传输,而一般网站视图函数则是获取数据后传递给前端模板以供展示。

    相关文章

      网友评论

        本文标题:基于Django Rest框架实现API构建

        本文链接:https://www.haomeiwen.com/subject/jufujrtx.html