AI智能
改变未来

用Django Rest Framework实现豆瓣API


一,创建开发环境

1,创建项目

项目名book,应用名users:

django-admin startproject bookdjango-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 modelsfrom 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_namedef __str__(self):return self.username

还要在setting.py中完成扩展用户模型所需的的相关配置:

AUTH_USER_MODEL=\'users.UserProfile\'

5,创建书籍信息模型

在users/models.py中创建书籍信息模型:

from datetime import datetimefrom django.db import modelsclass 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_namedef __str__(self):return self.title

6,数据迁移及数据添加

执行数据迁移命令,据模型创建数据表:

python manage.py makemigrationspython manage.py migrate

在users_book表中添加书籍信息:

7,创建超级用户

python manage.py createsuperuser

二,使用Serializer实现序列化

1,序列化类

使用Serializer方法序列化书籍信息:

users/serializers.py:from rest_framework import serializersfrom .models import UserProfile, Bookclass 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 BookSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom .models import UserProfile, Bookclass 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 pathfrom users.views import BookAPIView1urlpatterns = [path(\'v1-1/\', BookAPIView1.as_view(), name=\'book1\'),]book/urls.py:from django.contrib import adminfrom django.urls import path, includeurlpatterns = [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 = Bookfields = \"__all__\"  # 将整个表的所有字段都序列化

2,基于类的序列化视图

users/views.py:from .serializers import BookModelSerializerfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom .models import UserProfile,Bookclass 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.moneyif 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-=1developer.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 pathfrom users.views import BookAPIView1, BookAPIView2urlpatterns = [path(\'v1-1/\', BookAPIView1.as_view(), name=\'book1\'),path(\'v1-2/\', BookAPIView2.as_view(), name=\'book2\'),]book/urls.py:from django.contrib import adminfrom django.urls import path, includeurlpatterns = [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.moneyif balance > 0:isbn = self.request.query_params.get(\"isbn\", 0)developer.money -= 1developer.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 BookModelSerializerfrom rest_framework.response import Responsefrom .models import UserProfile, Bookfrom rest_framework import mixinsfrom rest_framework import genericsclass BookMixinView2(generics.ListAPIView, generics.CreateAPIView):queryset = Book.objects.all()serializer_class = BookModelSerializerdef get(self, request, *args, **kwargs):APIKey = self.request.query_params.get(\"apikey\", 0)developer = UserProfile.objects.filter(APIkey=APIKey).first()if developer:balance = developer.moneyif balance > 0:isbn = self.request.query_params.get(\"isbn\", 0)developer.money -= 1developer.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 BookModelSerializerfrom rest_framework.response import Responsefrom .models import UserProfile,Bookfrom rest_framework import viewsetsfrom rest_framework.permissions import BasePermissionclass 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 Trueelse:print(self.message)return Falseclass 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.moneyif balance > 0:developer.money -= 1developer.save()return Trueelse:return Falseclass BookModelViewSet(viewsets.ModelViewSet):authentication_classes = []permission_classes = [IsDeveloper, EnoughMoney]queryset = Book.objects.all()serializer_class = BookModelSerializerdef get_queryset(self):isbn = self.request.query_params.get(\"isbn\", 0)books = Book.objects.filter(isbn=int(isbn))queryset=booksreturn queryseturls.py:from django.urls import path, includefrom users.views import *from rest_framework.routers import DefaultRouterrouter = 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——序列化。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 用Django Rest Framework实现豆瓣API