Django RESTframework 教程

介绍

前后端不分离

前后端分离

序列化和反序列化

序列化:将程序中的一个数据结构转化为其他格式(字典、JSON、xml等),例如django中将模型类对象转化为JSON字符串,这一过程被称为序列化。增改查,删不用返回

反序列化:修改和新增

  • 增:校验请求数据-> 执行反序列化 -> 保存数据库 -> 将保存的对象序列化输出
  • 删:判断要删除的数据是否存在 -> 执行数据库删除
  • 改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化返回
  • 查:查询数据库 -> 将数据库序列化返回

DRF作用

Django REST framework 可以帮助我们简化序列化和反序列化部分的代码编写,大大提高REST API的开发速度。

DRF特点

  • 提供了定义序列化器Serializer的方法,可以快速根据Django ORM 或者其他库自动序列化/反序列化
  • 提供了丰富的类视图、Mixin扩展类,简化视图的编写
  • 丰富的定制层级:函数视图、类视图、试图集合到自动生成API,满足各种需求
  • 多种身份认证和权限认证方式的支持
  • 内置了限流系统
  • 直观的API web界面
  • 可扩展性,插件丰富

相关文档

官方文档: http://www.django-rest-framework.org/

源码:https://github.com/encode/django-rest-framework/tree/master

DRF安装使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
## 环境依赖
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support

## Add 'rest_framework' to your INSTALLED_APPS setting.
INSTALLED_APPS = [
...
'rest_framework',
]

## If you're intending to use the browsable API you'll probably also want to add REST framework's login and logout views. Add the following to your root urls.py file.
urlpatterns = [
...
path('api-auth/', include('rest_framework.urls')) # Note that the URL path can be whatever you want.
]

##
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}

## 添加路由
from django.urls import path, include
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets

# Serializers define the API representation.
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'is_staff']

# ViewSets define the view behavior.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer

# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

DRF 序列化器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class BookInfo(models.Model):
btitle = models.CharField(max_length=30, verbose_name ='名称')
bup_date = models.DateField(auto_now=True, verbose_name='发布日期')

## 自定义序列化器
class BookInfoSerializer1(serializers.Serializer):
# read_only=True 只做序列化 write_only=True 只做反序列化
id = serializers.IntegerField(label="ID", read_only=True)
btitle = serializers.CharField(max_length=30, label='名称',required=True)
bup_date = serializers.DateField(label='发布日期')
hello = serializers.CharField(max_length=10) # 新添加的字段

from booktest.serializers import BookInfoSerializer, HeroInfoSerializer
from booktest.models import BookInfo, HeroInfo
book = BookInfo.objects.get(id=1)
s = BookInfoSerializer1(instance=book, many=False)
s.data

books = BookInfo.objects.all()
s = BookInfoSerializer1(instance=books, many=True)
s.data

  • 序列化器中的字段个数可以与模型的属性个数不同
    • 可以添加不存在的,也可以不写,但是不能修改
  • 创建序列化器有两个参数BookInfoSerializer(instance, data)
    • S = BookInfoSerializer(instance=book, many=true) 只做序列化, S.data 可以取值
      • 序列化 == 模型数据 -> python字典(用于输出,返回数据给前端)
    • S = BookInfoSerializer(data=data) 只做反序列化
      • 反序列化 == 前端发送的数据 -> 经过验证 -> python字典 ->save ->模型类对象(用于输入,接受前端数据)

jsonresponse 如果返回的是列表,safe=False; 序列化如果是一个查询集合,many=True

DRF 关联序列化

1
2
3
4
5
6
7
8
9
10
11
# 只能序列化输出, 默认是将关联模型的ID序列化
hbook = serializers.PrimaryKeyRelatedField(label="书籍",read_only=True)

# 默认是将关联模型的__str__方法返回值序列化
hbook = serializers.StringRelatedField(label="书籍", read_only=True)

# 关联模型对象的序列化器中所有字段序列化出来
hbook = BookInfoSerializer1(read_only=True)

# 如果一里面关联序列化多时,需要指定many=True
heroinfo_set = HeroInfoSerializer1(many=True)

两个序列化器只能一个做关联

DRF 反序列化

  • is_valid()方法 :在获取序列化的数据前,通过该方法进行验证
  • errors属性: 验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典
  • validated_data属性: 验证成功,获取数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
data = {
'btitle': '三国'
}

serializer = BookInfoSerializer(data=data)
serializer.is_valid() # 调用序列化器的校验方法, True或False【必须执行】
serializer.is_valid(raise_exception=True) # 校验出错后,自动抛出错误信息
serializer.errors # 获取校验的错误信息,可不用,用上面这一个
serializer.validated_data # 获取反序列化校验后的数据还是字典【然后执行】

## 额外对某些字段进行校验
class BookInfoSerializer1(serializers.Serializer):
# read_only=True 只做序列化 write_only=True 只做反序列化
id = serializers.IntegerField(label="ID", read_only=True)
btitle = serializers.CharField(max_length=30, label='名称',required=True)
bup_date = serializers.DateField(label='发布日期')
hello = serializers.CharField(max_length=10) # 新添加的字段
## 以下是反序列化进行的操作
def validate_btitle(self, value): # 对某字段单独添加校验,注意命名
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value
def validate(self, attrs):
# 多个字段进行联合校验
attrs["hello"] = "word" # 添加数据
return attrs
def validate_btitle(self, value): # 对某字段单独添加校验,注意命名
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value
def create(self, validated_data):
# validated_data 反序列化校验后的字典型数据
# 当调用序列化器的save方法时,如果当初创建序列化器对象是没有给instance传参数
book = BookInfo.objects.create(**validated_data)
BookInfo.objects.create(**{'btitle':'三国'}) # 将字典 转换成 关键字=value 这种格式
BookInfo.objects.create(
btitle="三国"
)
return book
def update(self, instance, validated_data):
# 如果传入参数,实际上会调用该方法
instance.btitle = validated_data.get('btitle')
instance.save()
return instance

## 校验成功后操作
serializer.save() # 会执行序列化器中的create方法或update方法