现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式。前后端分离方式有许多好处,比如 1、可以前后端并行开发,提高开发效率 2、页面都在客户端进行渲染,提高了渲染速度,减小了服务器的压力 3、一套api提供给多个客户端使用,而且不限制客户端的类型(web,app均可)
提到前后端分离必然会提到restful,目标这是最流行的接口规范,想要了解的可以去阮老师的博客看一下 越来越多的大型应用开始使用restful规范,restful强调一种无状态,资源的方式 在django中很著名的一个框架是django-rest-framework,帮我们减少了很多工作量,尤其在序列化与反序列化成我们需要的格式帮了我们省了很多事 在这里就记录一下个人的学习过程
django-rest-framework
实现一组api的基本流程
- 在models.py中创建自己需要的数据模型
- 创建serializers.py在其中写出适合的serializer类,能够正确的序列化与反序列化
- 在views.py中写出合适的api类,只需要继承rest_framework中generics中的某个类,重写我们需要的方法实现合适的逻辑即可
- 在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
其实默认最少只要实现两个参数或方法即可queryset和serializer_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中测试成功
- 上述文字皆为个人看法,如有错误或建议请及时联系我