用Django Rest Framework模拟豆瓣API

导读:本篇文章讲解 用Django Rest Framework模拟豆瓣API,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一,创建开发环境

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——序列化

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/98148.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!