django-rest-framework框架学习

2020-09-24 11:33:18 浏览数 (1)

现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式。前后端分离方式有许多好处,比如 1、可以前后端并行开发,提高开发效率 2、页面都在客户端进行渲染,提高了渲染速度,减小了服务器的压力 3、一套api提供给多个客户端使用,而且不限制客户端的类型(web,app均可)

提到前后端分离必然会提到restful,目标这是最流行的接口规范,想要了解的可以去阮老师的博客看一下 越来越多的大型应用开始使用restful规范,restful强调一种无状态,资源的方式 在django中很著名的一个框架是django-rest-framework,帮我们减少了很多工作量,尤其在序列化与反序列化成我们需要的格式帮了我们省了很多事 在这里就记录一下个人的学习过程

django-rest-framework

实现一组api的基本流程

  1. models.py中创建自己需要的数据模型
  2. 创建serializers.py在其中写出适合的serializer类,能够正确的序列化与反序列化
  3. views.py中写出合适的api类,只需要继承rest_frameworkgenerics中的某个类,重写我们需要的方法实现合适的逻辑即可
  4. urls.py中配置所需要的url

一组api的demo

创建一个model

在创建好的app下的model.py中创建一个student模型

代码语言:javascript复制
class Student(models.Model):
    student_id = models.IntegerField()
    name = models.CharField(max_length=20)
    age = models.IntegerField()

例子很简单,三个字段,分别表示学号,姓名,年龄

然后同步数据库,在数据库中创建表 在终端中输入

代码语言:javascript复制
python manage.py makemigrations

python manage.py migrate

在数据库里插入几条测试数据后如图所示

实现序列化类

官方文档:http://www.django-rest-framework.org/api-guide/serializers/ 创建serializers.py在其中实现序列化类 由于这个序列化是和我们的模型想对应的相关,所以可以直接继承serializers.ModelSerializer

代码语言:javascript复制
class StudentSerializer(serializers.ModelSerializer):

    class Meta:
        model = Student
        fields = ('id', 'student_id', 'name', 'age')

其他相关的参数可以查阅官方文档,都有详细的介绍 这里我们只简单的显示所有的字段

实现视图api类

官方文档: http://www.django-rest-framework.org/api-guide/generic-views/

在这里只需要继承相关的类,复写父类方法即可

代码语言:javascript复制
# 学生列表
class StudentList(generics.ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    # 创建一个student
    def create(self, request, *args, **kwargs):
        serializer = StudentSerializer(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 StudentDetail(generics.RetrieveUpdateAPIView):
    serializer_class = StudentSerializer
    queryset = Student.objects.all()
    lookup_field = 'name'

    # 得到一个数据集
    def get_queryset(self):
        return Student.objects.filter(name=self.kwargs['name'])

    # get方法返回一个student
    def get(self, request, *args, **kwargs):
        # 获取url中的参数
        # http://127.0.0.1:8000/api/students/aaa/?test=123
        # 取test的值
        print(self.request.GET.get('test', None))

        queryset = self.get_queryset()
        serializer = StudentSerializer(queryset, many=True)
        return Response({
            'data': serializer.data,
            #'sorce': StudentSorceSerializer(StudentSorce.objects.all(), many=True).data
        })

    # 更新某一个学生的信息
    def update(self, request, *args, **kwargs):
        pass

其实默认最少只要实现两个参数或方法即可querysetserializer_class 但很多时候逻辑需要自己处理,必须按照自己的逻辑去复写父类属性 在get方法中的self.request.GET.get(‘test’, None)是取出get方法传递的参数 lookup_field 应用于执行单个模型实例的对象查找的模型字段。默认为’pk’。请注意,使用超链接的API时,您需要确保双方的API意见和串行类设置查找字段,如果你需要使用一个自定义值 在get_queryset()中实现的是按照name查询的,因为很多时候客户端并不知道自己的id是多少, serializer.data是对模型序列化成的字典,如果想拼成需要的格式,需要提前构造合适的字典,在用Response()方法帮我们序列化成json类型

在urls中自定义资源的url

urls.py中输入

代码语言:javascript复制
from django.conf.urls import url
from .views import StudentList, StudentDetail

urlpatterns = [
    url(r'students/$', StudentList.as_view()),
    url(r'students/(?P<name>[a-zA-Z] )/$', StudentDetail.as_view()),
]

分别配置好对列表和单个的url

然后运行项目就可以看到我们需要的数据

完整代码

在原来的基础上进行了扩展,在显示学生信息的基础上,我们还想显示该名学生的成绩 所以新的model.py

代码语言:javascript复制
from django.db import models

class Student(models.Model):
    student_id = models.IntegerField()
    name = models.CharField(max_length=20)
    age = models.IntegerField()

class StudentSorce(models.Model):
    student_id = models.IntegerField()
    math = models.FloatField()
    english = models.FloatField()
    chiness = models.FloatField()

我们在这里没有使用外键,毕竟现在很多大牛说不使用外键,在应用中控制逻辑嘛 当然这里也可以使用models.ForeignKey,会让操作变得更简单的一点

serializers.py为:

代码语言:javascript复制
from rest_framework import serializers
from api.models import Student, StudentSorce

class StudentSorceSerializer(serializers.ModelSerializer):
    avg = serializers.SerializerMethodField('get_avg_sorce')

    class Meta:
        model = StudentSorce
        fields = ('math', 'english', 'chiness', 'avg')
    # 自定义方法构造的字段(计算成绩的平均值)
    def get_avg_sorce(self, obj):
        return (obj.math   obj.english   obj.chiness) / 3.0

class StudentSerializer(serializers.ModelSerializer):
    sorce = serializers.SerializerMethodField('get_student_sorce')

    class Meta:
        model = Student
        fields = ('id', 'student_id', 'name', 'age', 'sorce')
    # 使用学号查出该学生的成绩
    def get_student_sorce(self, obj):
        print obj.student_id
        return StudentSorceSerializer(StudentSorce.objects.filter(student_id=obj.student_id), many=True).data

views.py为:

代码语言:javascript复制
# coding:utf-8
from __future__ import print_function
from django.shortcuts import render
from rest_framework import generics
from api.serializers import StudentSerializer
from .models import Student, StudentSorce
from rest_framework.response import Response
from rest_framework import status
from api.serializers import StudentSorceSerializer

# 学生列表
class StudentList(generics.ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    # 创建一个student
    def create(self, request, *args, **kwargs):
        serializer = StudentSerializer(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)

    '''
    def list(self, request, *args, **kwargs):
        print('list')
        return Response(StudentSerializer(Student.objects.filter(student_id__gt=102), many=True).data)
        '''

# 单个学生
class StudentDetail(generics.RetrieveUpdateAPIView):
    serializer_class = StudentSerializer
    queryset = Student.objects.all()
    lookup_field = 'name'

    # 得到一个数据集
    def get_queryset(self):
        return Student.objects.filter(name=self.kwargs['name'])

    # get方法返回一个student
    def get(self, request, *args, **kwargs):
        # 获取url中的参数
        # http://127.0.0.1:8000/api/students/aaa/?test=123
        # 取test的值
        print(self.request.GET.get('test', None))

        queryset = self.get_queryset()
        serializer = StudentSerializer(queryset, many=True)
        return Response({
            'data': serializer.data,
            'sorce': StudentSorceSerializer(StudentSorce.objects.all(), many=True).data
        })

    # 更新某一个学生的信息
    def update(self, request, *args, **kwargs):
        pass

注册功能

官方文档:http://www.django-rest-framework.org/api-guide/serializers/ 在这里我们使用django自带的auth模块 只需要修改serializer.py和view.py和urls.py三个文件即可 serializers.py

代码语言:javascript复制
# coding=utf-8
import re
from rest_framework import serializers
from django.contrib.auth.models import User

class AccountFrom(object):
    def __init__(self, email, username, password, repeat_password):
        self.email = email
        self.username = username
        self.password = password
        self.repeat_password = repeat_password


class AccountSerializer(serializers.Serializer):
    email = serializers.EmailField()
    username = serializers.CharField()
    password = serializers.CharField()
    repeat_password = serializers.CharField()

    def create(self, validated_data):
        User.objects.create_user(username=validated_data.get('username'),
                                 email=validated_data.get('email'),
                                 password=validated_data.get('password'))
        return AccountFrom(username=validated_data.get('username'),
                           email=validated_data.get('email'),
                           password=validated_data.get('password'),
                           repeat_password=validated_data.get('repeat_password'))

    def update(self, instance, validated_data):
        instance.email = validated_data.get('email', instance.email)
        instance.username = validated_data.get('username', instance.username)
        instance.password = validated_data.get('password', instance.password)
        # User.objects.update()
        instance.save()
        return instance

    def validate_email(self, value):
        try:
            result_email = User.objects.get(email=value)
        except User.DoesNotExist:
            return value
        raise serializers.ValidationError('该邮箱已注册')

    def validate_password(self, value):
        self.password = value
        if re.match('^(?![0-9] $)(?![a-zA-Z] $)[0-9A-Za-z]{6,20}$', value):
            return value
        else:
            raise serializers.ValidationError('密码必须由6-20个字母和数字组成')

    def validate_repeat_password(self, value):
        self.repeat_password = value
        if self.password and value and self.password != value:
            raise serializers.ValidationError("两次输入的值不相同")
        return value

    def validate_username(self, value):
        if re.match("^[A-Za-z][A-Za-z0-9_.]*$", value):
            return value
        else:
            raise serializers.ValidationError("用户名只能有数字字母下划线组成")

以validate_开头后面接字段名的函数均为验证函数,如果不符合验证规则,将返回异常信息

views.py

代码语言:javascript复制
# 注册模块
class AccountDetail(generics.CreateAPIView):
    serializer_class = AccountSerializer
    queryset = User.objects.all()

    def create(self, request, *args, **kwargs):
        serializer = AccountSerializer(data=request.data, partial=True)
        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)

继承generics.CreateAPIView只允许http的post方法 这里只简单实现了用户注册

url.py

代码语言:javascript复制
urlpatterns = [
    url(r'register/$', AccountDetail.as_view()),
]

访问http://127.0.0.1:8000/account/register,提供合法的email、username、password、repeat_password将会创建一个账户

注:

  • 上述环境在ubuntu16.04 lts django1.9 djangorestframework3.6.2中测试成功
  • 上述文字皆为个人看法,如有错误或建议请及时联系我

0 人点赞