专栏首页earthchen的专栏django-rest-framework框架学习

django-rest-framework框架学习

现在新一代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模型

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

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

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

python manage.py makemigrations

python manage.py migrate

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

实现序列化类

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

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/

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

# 学生列表
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中输入

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

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为:

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为:

# 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

# 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

# 注册模块
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

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 条评论
登录 后参与评论

相关文章

  • java面试知识要点汇总(基础和集合)

    反射机制是Java语言中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也允许对其内部成员进行操作。反射机制提供的功能主要有:得到一个对象所属的类;获取...

    用户1637228
  • JVM 类加载机制详解

    jvm将class文读取到内存中,经过对class文件的校验、转换解析、初始化最终在jvm的heap和方法区分配内存形成可以被jvm直接使用的类型的过程。

    用户1637228
  • java泛型总结

    泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。

    用户1637228
  • Sophon+Slipstream实现流式KMeans聚类预测

    随着数据规模和丰富度的不断提升,其价值越来越受到企业的重视。其中,机器学习在挖掘数据价值方面扮演着重要的角色,得到广泛应用。大数据概念的在各行各业的普及与深入,...

    企鹅号小编
  • Python-集合数据类型内置方法

    py3study
  • latex中的希腊字母

    希腊字母,我们从小学开始认识它,但对它的读音我依旧靠蒙(说蒙真的感觉好羞愧啊)。尤其在大学数学分析中,希腊字母超级多,很多经典的公式,都由希腊字母来表示。它自然...

    努力在北京混出人样
  • 专访微软谢幸博士:如何将推荐系统与异构数据巧妙结合

    用户1737318
  • 类器官:肿瘤研究的新高地

    每年肿瘤相关研究的学术论文发表量数以万计,但能真正转化到临床应用的治疗方案却极少。新药研发进入临床试验后,有85%在早期就被证明没有效果,而那些成功通过三期临床...

    用户6317549
  • 贷款应用被拒如何应对?怎么上架(含隐藏开关)的马甲包

          突然间的2.1大礼包成了一个重灾区,苹果加大了中国区的审核力度。但其实归根结底,会触犯到这个大礼包的App很大部分或者说几乎都是和这个关键词挂钩的 ...

    jiang chen
  • 从特斯拉到英伟达,那些端到端自动驾驶研发系统有何不同?

    Nvidia是比较早做端到端控制车辆工作的公司,其方法训练CNN模型完成从单个前向摄像头的图像像素到车辆控制的映射。 其系统自动学习一些处理步骤的内部表示,比如...

    AI科技大本营

扫码关注云+社区

领取腾讯云代金券