用Django Rest Framework实现豆瓣API
一,创建开发环境
1,创建项目
项目名book,应用名users:
django-admin startproject book django-admin startapp users
2,安装DRF
pip install djangorestframework markdown django-filter
3,配置settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'users.apps.UsersConfig', 'rest_framework' ]
4,创建用户模型
在users/models.py中扩展内置用户模型:
from django.db import models from django.contrib.auth.models import AbstractUser # Create your models here. class UserProfile(AbstractUser): """ 用户额度表 """ APIkey = models.CharField(max_length=30, verbose_name='APIkey', default='abcdefghigklmn') money = models.IntegerField(default=10, verbose_name='余额') class Meta: verbose_name = '用户额度表' verbose_name_plural = verbose_name def __str__(self): return self.username
还要在setting.py中完成扩展用户模型所需的的相关配置:
AUTH_USER_MODEL='users.UserProfile'
5,创建书籍信息模型
在users/models.py中创建书籍信息模型:
from datetime import datetime from django.db import models class Book(models.Model): """ 书籍信息 """ title=models.CharField(max_length=30,verbose_name='书名',default='') isbn=models.CharField(max_length=30,verbose_name='isbn',default='') author=models.CharField(max_length=20,verbose_name='作者',default='') publish=models.CharField(max_length=30,verbose_name='出版社',default='') rate=models.FloatField(default=0,verbose_name='豆瓣评分') add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间') class Meta: verbose_name='书籍信息' verbose_name_plural = verbose_name def __str__(self): return self.title
6,数据迁移及数据添加
执行数据迁移命令,据模型创建数据表:
python manage.py makemigrations python manage.py migrate
在users_book表中添加书籍信息:
7,创建超级用户
python manage.py createsuperuser
二,使用Serializer实现序列化
1,序列化类
使用Serializer方法序列化书籍信息:
users/serializers.py: from rest_framework import serializers from .models import UserProfile, Book class BookSerializer(serializers.Serializer): title = serializers.CharField(required=True, max_length=100) isbn = serializers.CharField(required=True, max_length=100) author = serializers.CharField(required=True, max_length=100) publish = serializers.CharField(required=True, max_length=100) rate = serializers.FloatField(default=0) add_time = serializers.DateTimeField(format="%Y-%m-%d", required=False, read_only=True)
2,基于类的序列化视图
users/views.py: from .serializers import BookSerializer from rest_framework.views import APIView from rest_framework.response import Response from .models import UserProfile, Book class BookAPIView1(APIView): """ 基于APIView类的序列化视图,这里暂时只对GET请求进行处理与响应。 """ def get(self, request, format=None): # format为api添加可选后缀 APIKey = self.request.query_params.get("apikey", 0) # 获取请求中的apikey print('request:\n', request.query_params) # <QueryDict: {'apikey': ['abcdefghigklmn'], 'isbn': ['119']}> developer = UserProfile.objects.filter(APIkey=APIKey).first() # 根据获取请求中的apikey查询数据 if developer: # 数据存在 balance = developer.money # 获取所需细节数据 if balance > 0: isbn = self.request.query_params.get("isbn", 0) books = Book.objects.filter(isbn=int(isbn)) books_serializer = BookSerializer(books, many=True) # 序列化数据 developer.money -= 1 # 可用次数自动减少 developer.save() # 重新保存查询集 return Response(books_serializer.data) # 使用DRF的Response获得更友好的数据格式 else: return Response("兄弟,又到了需要充钱的时候!好开心啊!") else: return Response("查无此人啊")
3,路由
users/urls.py: from django.urls import path from users.views import BookAPIView1 urlpatterns = [ path('v1-1/', BookAPIView1.as_view(), name='book1'), ] book/urls.py: from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('apibook/', include(('users.urls', 'users')), name='book'),]
4,运行
访问http://127.0.0.1:8000/apibook/v1-1/?apikey=abcdefghigklmn&isbn=119
三,使用Serializer实现序列化
1,序列化类
ModelSerializer简化了序列化工作。
users/serializers.py: class BookModelSerializer(serializers.ModelSerializer): class Meta: model = Book fields = "__all__" # 将整个表的所有字段都序列化
2,基于类的序列化视图
users/views.py: from .serializers import BookModelSerializer from rest_framework.views import APIView from rest_framework.response import Response from .models import UserProfile,Book class BookAPIView2(APIView): """ 使用ModelSerializer """ def get(self, request, format=None): APIKey=self.request.query_params.get("apikey", 0) developer=UserProfile.objects.filter(APIkey=APIKey).first() if developer: balance=developer.money if balance>0: isbn = self.request.query_params.get("isbn", 0) books = Book.objects.filter(isbn=int(isbn)) books_serializer = BookModelSerializer(books, many=True) developer.money-=1 developer.save() return Response(books_serializer.data) else: return Response("兄弟,又到了需要充钱的时候!好开心啊!") else: return Response("查无此人啊") def post(self, request, format=None): serializer = BookModelSerializer(data=request.data) if serializer.is_valid(): print('serializers:', serializer) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3,路由
users/urls.py: from django.urls import path from users.views import BookAPIView1, BookAPIView2 urlpatterns = [ path('v1-1/', BookAPIView1.as_view(), name='book1'), path('v1-2/', BookAPIView2.as_view(), name='book2'), ] book/urls.py: from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('apibook/', include(('users.urls', 'users')), name='book'), ]
4,运行
访问http://127.0.0.1:8000/apibook/v1-2/?apikey=abcdefghigklmn&isbn=119
到此为止,都还只是进行简单的序列化操作。
四,选择合适的类视图封装方式
关于通用视图、视图集的知识,可以参考DRF官网API。
1,mixins + GenericAPIView
GenericAPIView类扩展了REST framework 的 APIView 类,为标准列表和详细视图添加了通常所需的行为。每个具体的通用视图都是通过将 GenericAPIView 类和一个或多个 minxin 类相互结合来构建的。
mixins.ListModelMixin类提供 .list(request,*args,**kwargs) 方法。
class BookMixinView1(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = Book.objects.all() # 必须设置 serializer_class = BookModelSerializer # 必须设置 def get(self, request, *args, **kwargs): APIKey = self.request.query_params.get("apikey", 0) developer = UserProfile.objects.filter(APIkey=APIKey).first() if developer: balance = developer.money if balance > 0: isbn = self.request.query_params.get("isbn", 0) developer.money -= 1 developer.save() self.queryset = Book.objects.filter(isbn=int(isbn)) return self.list(request, *args, **kwargs) else: return Response("兄弟,又到了需要充钱的时候!好开心啊!") else: return Response("查无此人啊") def post(self, request, *args, **kwargs): serializer = BookModelSerializer(data=request.data) if serializer.is_valid(): return self.create(request, *args, **kwargs) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
访问http://127.0.0.1:8000/apibook/v1-3/?apikey=abcdefghigklmn&isbn=119,并提交新数据。
访问http://127.0.0.1:8000/apibook/v1-3/?apikey=abcdefghigklmn&isbn=123,查看提交的新数据。
2,使用具体视图类
具体视图类对通用基类进行进一步封装。
from .serializers import BookModelSerializer from rest_framework.response import Response from .models import UserProfile, Book from rest_framework import mixins from rest_framework import generics class BookMixinView2(generics.ListAPIView, generics.CreateAPIView): queryset = Book.objects.all() serializer_class = BookModelSerializer def get(self, request, *args, **kwargs): APIKey = self.request.query_params.get("apikey", 0) developer = UserProfile.objects.filter(APIkey=APIKey).first() if developer: balance = developer.money if balance > 0: isbn = self.request.query_params.get("isbn", 0) developer.money -= 1 developer.save() self.queryset = Book.objects.filter(isbn=int(isbn)) return self.list(request, *args, **kwargs) else: return Response("兄弟,又到了需要充钱的时候!好开心啊!") else: return Response("查无此人啊") def post(self, request, *args, **kwargs): serializer = BookModelSerializer(data=request.data) if serializer.is_valid(): print('serializers:', serializer) return self.create(request, *args, **kwargs) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
访问http://127.0.0.1:8000/apibook/v1-4/?apikey=abcdefghigklmn&isbn=123
在上个链接中提交一个新数据,并进行查看:
3,使用ViewSets + Router
from .serializers import BookModelSerializer from rest_framework.response import Response from .models import UserProfile,Book from rest_framework import viewsets from rest_framework.permissions import BasePermission class IsDeveloper(BasePermission): message='查无此人啊' def has_permission(self,request,view): APIKey = request.query_params.get("apikey", 0) developer = UserProfile.objects.filter(APIkey=APIKey).first() if developer: return True else: print(self.message) return False class EnoughMoney(BasePermission): message = "兄弟,又到了需要充钱的时候!好开心啊!" def has_permission(self,request,view): APIKey = request.query_params.get("apikey", 0) developer = UserProfile.objects.filter(APIkey=APIKey).first() balance = developer.money if balance > 0: developer.money -= 1 developer.save() return True else: return False class BookModelViewSet(viewsets.ModelViewSet): authentication_classes = [] permission_classes = [IsDeveloper, EnoughMoney] queryset = Book.objects.all() serializer_class = BookModelSerializer def get_queryset(self): isbn = self.request.query_params.get("isbn", 0) books = Book.objects.filter(isbn=int(isbn)) queryset=books return queryset urls.py: from django.urls import path, include from users.views import * from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register('', BookModelViewSet) urlpatterns = [ path('v1-5/', include(router.urls)), ]
访问http://127.0.0.1:8000/apibook/v1-5/?apikey=abcdefghigklmn&isbn=124:
在上个链接中提交一个新数据,并进行查看:
四,序列化嵌套
这个演示项目不存在表与表间的数据关联,就不需要对数据进行序列化的嵌套,但实际中,表与表间的数据关系存在一对一、一对多和多对多三种情况,每种不同情况使用的嵌套方式也不同。
这有一个对一对多数据关系进行嵌套的例子:django:Django Rest Framework——序列化。
- 使用Django REST Framework来快速实现API调用服务——下篇(编写API服务)
- 使用Django REST Framework来快速实现API调用服务——上篇(运行环境和模型层)
- Django笔记 Django REST Framework实现Web API 1
- 利用 Django REST framework 编写 RESTful API
- DJANGO的API跨域实现
- Django REST Framework实现动态序列化数据及动态分配权限
- django rest framework 实现用户登录认证详解
- Django Rest framework之认证的实现代码
- 如何使用Celery在DRF(Django rest framework)中提高服务器并发实现
- 使用Restframework+django_filters快速实现Django的API
- Django REST framework 分页的实现代码
- piston-在django中实现REST风格的API
- Django REST framework-API指南02-Responses 原创翻译
- Django REST FrameWork中文教程5:关系和超链接API
- BAE+Python+Django+Wechatpy+Baidu weather api +微信订阅号 = 实现微信查询天气
- Django Rest Framework 电商项目 8-1 ViewSets实现商品详情页
- Django Rest Framework源码剖析(四)-----API版本
- Django REST framework-API指南03-Class-based Views 原创翻译
- piston-在django中实现REST风格的API
- 如何实现Django Rest framework版本控制