Django-Rest-Framework代码记录

主要文件代码

[TOC]

表结构设计

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
# models.py 文件
from django.db import models

BOOK_CATEGORIES = ((1, 'Python'), (2, 'Linux'), (3, 'Go'))

__all__ = ['Book', 'Author', 'Publisher']


class Book(models.Model):
title = models.CharField(max_length=32)
category = models.IntegerField(choices=BOOK_CATEGORIES)
pub_date = models.DateField()
authors = models.ManyToManyField(to='Author')
publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE)

def __str__(self):
return self.title


class Author(models.Model):
name = models.CharField(max_length=32)

def __str__(self):
return self.name


class Publisher(models.Model):
title = models.CharField(max_length=32)
address = models.CharField(max_length=32)

def __str__(self):
return self.title

自定义Serializer

方式一:继承serializers.Serializer

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# serializers.py
from rest_framework import serializers
from appone.models import Book


class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)


class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)


SENSITIVE_WORDS = ['极品', '最美', '之王', '之最']


def my_validator(value):
"""
自定义过滤器,可以传到字段的validators参数中
:param value:
:return:
"""
if value in SENSITIVE_WORDS:
raise serializers.ValidationError("含有敏感词汇")


class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False) # required为False时,反序列化不做校验
title = serializers.CharField(max_length=32, validators=[my_validator,])
pub_date = serializers.DateField()
category = serializers.CharField(source="get_category_display", read_only=True)
post_category = serializers.IntegerField(write_only=True) # 序列化不做校验,反序列化做校验

# 内部通过外键关系的Id拿到publisher_obj,然后把publisher_obj传入PublisherSerializer序列化器进行序列化
publisher = PublisherSerializer(read_only=True)
authors = AuthorSerializer(many=True, read_only=True)
publisher_id = serializers.IntegerField(write_only=True) # 反序列化时使用,前端传数据时以此名称作为建
author_list = serializers.ListField(write_only=True) # 反序列化时使用

def create(self, validated_data):
book_obj = Book.objects.create(
title=validated_data['title'],
pub_date=validated_data['pub_date'],
category=validated_data['post_category'],
publisher_id=validated_data['publisher_id']
)
book_obj.authors.add(*validated_data['author_list'])
return book_obj

def update(self, instance, validated_data):
instance.title = validated_data.get('title', instance.title)
instance.pub_date = validated_data.get('pub_date', instance.pub_date)
instance.category = validated_data.get('post_category', instance.category)
instance.publisher_id = validated_data.get('publisher_id', instance.publisher_id)
if validated_data.get('author_list'):
instance.authors.set(validated_data['author_list'])
instance.save()
return instance

def validate_title(self, value):
"""
相当于局部钩子
:param value: 具体字段的值
:return:
"""
for word in SENSITIVE_WORDS:
if word in value:
raise serializers.ValidationError('标题含有敏感词汇')
return value

def validate(self, attrs):
"""
相当于全局钩子
:param attrs: 所有字段组成的字典
:return:
"""
print("attrs:", attrs)
return attrs
"""
继承serializers.Serializer自定义的Serializer中,必须定义create和update方法;当前端提交数据时,会在自定义的Serializer中查找create方法,当前端更新数据时,会在自定义的Serializer中查找update方法。

添加新书时,前端传输数据示例:
# 字段名称根据你创建的Serializer类中,为有外键关系字段定义的用于反序列化的具体名称决定
{
"title": "自然语言处理",
"pub_date": "2017-05-20",
"post_category": 1,
"publisher_id": 2,
"author_list": [1, 2]
}
"""

方式二:继承serializers.ModelSerializer

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
class BookSerializer(serializers.ModelSerializer):
# 有外键关系的字段和choices等一些特殊的字段,需要自定义展示效果;此处自定义的字段,在本类中必须有名称"get_字段"的钩子函数与其对应
# 注意:自定义的名字不要与原表中的字段名冲突
publisher_name = serializers.SerializerMethodField(read_only=True)
authors_info = serializers.SerializerMethodField(read_only=True)
category_name = serializers.SerializerMethodField(read_only=True)

# 这是个钩子函数,会自动触发,此方法的返回值会赋值给上方的publisher_name
def get_publisher_name(self, obj):
return obj.publisher.title

def get_authors_info(self, obj):
author_queryset = obj.authors.all()
return [{'id': author.id, 'name': author.name} for author in author_queryset]

def get_category_name(self, obj):
return obj.get_category_display()

class Meta:
model = Book
fields = '__all__'
# depth = 1 # 有外键关系的向下查找深度
extra_kwargs = {
"publisher": {"write_only": True},
"authors": {"write_only": True},
"category": {"write_only": True}
}
"""
继承serializers.ModelSerializer自定义的Serializer中,不用自定义create和update方法
read_only=True 只在序列化时(后端传数据给前端浏览器用于展示),对字段进行校验
write_only=True 只在反序列化时(后端拿到前端传过来的数据),对字段进行校验

添加新书时,前端传输数据示例:
{
"publisher": 1,
"authors": [1],
"category": "1",
"title": "Python袖珍指南",
"pub_date": "2015-08-25"
}
"""

路由文件

项目的路由

1
2
3
4
5
6
7
8
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include("appone.urls")),
url(r'^rest/', include("apprest.urls"))
]

应用的路由

1
2
3
4
5
6
7
8
# urls.py
from django.conf.urls import url
from .views import BookView, BookEditView

urlpatterns = [
url(r'^book$', BookView.as_view()),
url(r'^book/(?P<id>\d+)', BookEditView.as_view()),
]

视图函数文件

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
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from appone.models import Book
from .serializers import BookSerializer


class BookView(APIView):
def get(self, request):
book_queryset = Book.objects.all()
ser_obj = BookSerializer(book_queryset, many=True) # 如果传给BookSerializer的第一个参数只是一个对象,many=True可以省略
# print(request.query_params) # <QueryDict: {'format': ['api'], 'name': ['jason']}>
return Response(ser_obj.data)

def post(self, request):
book_data = request.data
ser_obj = BookSerializer(data=book_data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data)
return Response(ser_obj.errors) # 前端提交过来数据校验未通过,返回错误信息给前端


class BookEditView(APIView):
def get(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(book_obj)
return Response(ser_obj.data)

def put(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
# partial=True表示允许校验部分字段,因为更改图书对象时,可能只是更改一个或几个字段;如果不设置partial=True,那么前端传过来的数据必须包含所有必须的字段,即字段要完整
if ser_obj.is_valid():
print(ser_obj.validated_data)
ser_obj.save()
return Response(ser_obj.validated_data)
return Response(ser_obj.errors)
感谢您的支持!学如逆水行舟,不进则退!