在本篇文章中,我们将详细介绍如何使用 Django REST Framework (简称 DRF)开发一个简单的 API 接口。我们将从创建数据库、定义模型、编写序列化器,到实现视图函数以及路由配置,逐步展开,带你了解完整的开发流程。无论你是刚接触 Django 的开发者,还是希望通过 DRF 快速构建 RESTful API 的开发者,都能从中获得清晰的思路和实用的技巧。
1.文件结构 如下是本篇完成后的项目文件结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 . ├── data │ ├── mysql │ └── redis ├── docker-compose.yml ├── Dockerfile ├── myproject │ ├── manage.py │ ├── myapp │ │ ├── admin.py │ │ ├── apps.py │ │ ├── __init__.py │ │ ├── models.py │ │ ├── serializers.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ └── myproject │ ├── asgi.py │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── requirements.txt
2.创建数据库 首先进入mysql容器创建一个数据库:
1 2 3 4 5 6 docker exec -it django-tutorial-mysql-1 /bin/sh mysql -u root -p root CREATE DATABASE django_demo default charset=utf8mb4;
3.docker-compose.yml 在docker-compose中进行数据库迁移,然后启动服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 services: web: build: . privileged: true command: - sh - -c - python manage.py migrate python manage.py runserver 0.0 .0 .0 :5000 volumes: - ./data/myproject/myapp/migrations:/code/myproject/myapp/migrations ...
4.Dockerfile 在Dockerfile中注释掉启动命令:
5.myproject/settings.py 在配置文件中配置数据库连接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import pymysqlpymysql.install_as_MySQLdb() DATABASES = { 'default' : { 'ENGINE' : 'django.db.backends.mysql' , 'NAME' : 'django_demo' , 'USER' : 'root' , 'PASSWORD' : 'root' , 'HOST' : 'mysql' , 'PORT' : 3306 , 'CONN_MAX_AGE' : 10 , 'OPTIONS' : { 'init_command' : 'SET default_storage_engine=INNODB;' , 'charset' : 'utf8mb4' } } }
6.myapp/models.py 此处定义数据库模型,以通过 Django 的 ORM 操作数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from django.db import modelsclass Article (models.Model): title = models.CharField(max_length=90 , db_index=True ) body = models.TextField(blank=True ) create_date = models.DateTimeField(auto_now_add=True ) def __str__ (self ): return self .title class Meta : ordering = ['-create_date' ] verbose_name = "Article" verbose_name_plural = "Articles"
7.myapp/serializers.py 此处编写数据序列化代码,其主要用于Django模型实例->Python数据类型->前端JSON等格式的数据转换,或反向转换,并提供了强大的数据验证和自定义功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from rest_framework import serializersfrom .models import Articleclass ArticleSerializer (serializers.ModelSerializer): title = serializers.CharField(max_length=90 , required=True ) body = serializers.CharField(max_length=2048 , required=True ) create_date = serializers.DateTimeField(format ="%Y-%m-%d %H:%M:%S" , required=False , read_only=True ) class Meta : model = Article fields = '__all__'
8.myapp/views.py 此处编写视图代码,通过 API 视图(APIView
)来实现 GET、POST、PUT 和 DELETE 请求处理,实现基本的增删改查(CRUD)操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 from rest_framework import statusfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom django.http import Http404from .serializers import ArticleSerializerfrom .models import Articleclass ArticleList (APIView ): def get (self, request, format =None ): articles = Article.objects.all () serializer = ArticleSerializer(articles, many=True ) return Response(serializer.data) def post (self, request, format =None ): serializer = ArticleSerializer(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) class ArticleDetail (APIView ): def get_object (self, pk ): try : return Article.objects.get(pk=pk) except Article.DoesNotExist: raise Http404 def get (self, request, pk, format =None ): article = self .get_object(pk) serializer = ArticleSerializer(article) return Response(serializer.data) def put (self, request, pk, format =None ): article = self .get_object(pk) serializer = ArticleSerializer(instance=article, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def delete (self, request, pk, format =None ): article = self .get_object(pk) article.delete() return Response(status=status.HTTP_204_NO_CONTENT)
9.myapp/urls.py 此处为视图函数编写路由代码,将视图与 URL 路由关联,便于客户端请求访问。
1 2 3 4 5 6 7 8 9 10 11 from django.urls import re_pathfrom rest_framework.urlpatterns import format_suffix_patternsfrom . import viewsurlpatterns = [ re_path(r'^articles/$' , views.ArticleList.as_view()), re_path(r'^articles/(?P<pk>[0-9]+)$' , views.ArticleDetail.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
10.myproject/urls.py 此处引用路由文件,可以添加路由前缀:
1 2 3 4 5 6 from django.urls import path, includeurlpatterns = [ ... path('api/v1/' , include('myapp.urls' )), ]
11.测试 通过 curl
或其他 HTTP 客户端工具对 API 进行测试,验证接口的正确性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 docker-compose up -d --build web docker exec -it django-tutorial-web-1 /bin /sh python manage.py makemigrations myapp docker-compose restart web curl -H "Content-Type: application/json" -X POST -d '{"title":"mytitle", "body":"mybody"}' 127.0 .0 .1 :5000 /api/v1/articles/ {"id" :1 ,"title" :"mytitle" ,"body" :"mybody" ,"create_date" :"2023-10-23 09:17:35" } curl 127.0 .0 .1 :5000 /api/v1/articles/ [{"id" :1 ,"title" :"mytitle" ,"body" :"mybody" ,"create_date" :"2023-10-23 09:17:35" }] curl 127.0 .0 .1 :5000 /api/v1/articles/1 {"id" :1 ,"title" :"mytitle" ,"body" :"mybody" ,"create_date" :"2023-10-23 09:17:35" } curl -H "Content-Type: application/json" -X PUT -d '{"title":"notitle", "body":"nobody"}' 127.0 .0 .1 :5000 /api/v1/articles/1 {"id" :1 ,"title" :"notitle" ,"body" :"nobody" ,"create_date" :"2023-10-23 09:17:35" } curl -X DELETE 127.0 .0 .1 :5000 /api/v1/articles/1