restful-framwork-创新互联
1.RESTful规范
一 面向资源编程
每个URL代表一种资源,URL中尽量不要用动词,要用名词。
二 根据method不同,进行不同的操作
GET/POST/PUT/DELETE/PATCH
三 在URL中体现版本
https://www.bootcss.com/v1/mycss
https://v1.bootcss.com/mycss
四 在URL中体现是否是API
https://www.bootcss.com/api/mycss
https://api.bootcss.com/mycss
五 在URL中的过滤条件
https://www.bootcss.com/v1/mycss?page=3
六 尽量使用HTTPS
https://www.bootcss.com/v1/mycss
七 响应时设置状态码
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误
八 返回值
GET请求 返回查到所有或单条数据
POST请求 返回新增的数据
PUT请求 返回更新数据
PATCH请求 局部更新 返回更新整条数据
DELETE请求 返回值为空
九 返回错误信息
返回值携带错误信息
十 Hypermedia API
如果遇到需要跳转的情况 携带跳转接口的URL
ret = {
code: 1000,
data:{
id:1,
name:'小强',
depart_id:http://www.luffycity.com/api/v1/depart/8/
}
}
2.DRF序列化
2.1为什么要使用DRF来序列化
当我们做前后端分离的项目~~我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式。
那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿到的数据进行序列化。
接下来我们看下django序列化和rest_framework序列化的对比~~
2.2Django的序列化
#1.Jsonresponse序列化方式
class BooksView(View):
def get(self, request):
book_list = Book.objects.values("id", "title", "chapter", "pub_time", "publisher")
book_list = list(book_list)
# 如果我们需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成我们想要的
ret = []
for book in book_list:
pub_dict = {}
pub_obj = Publish.objects.filter(pk=book["publisher"]).first()
pub_dict["id"] = pub_obj.pk
pub_dict["title"] = pub_obj.title
book["publisher"] = pub_dict
ret.append(book)
ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
return HttpResponse(ret)
# json.JSONEncoder.default()
# 解决json不能序列化时间字段的问题
class MyJson(json.JSONEncoder):
def default(self, field):
if isinstance(field, datetime.datetime):
return field.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, datetime.date):
return field.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, field)
#2.Django序列化方法
from django.core import serializers
# 能够得到我们要的效果 结构有点复杂
class BooksView(View):
def get(self, request):
book_list = Book.objects.all()
ret = serializers.serialize("json", book_list)
return HttpResponse(ret)
2.3DRF的序列化
2.3.1drf序列化
-- Django我们CBV继承类是View,现在DRF我们要用APIView
-- Django中返回的时候我们用HTTPResponse,JsonResponse,render ,DRF我们用Response
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
# 这是为了显示choice字段的值
chapter = serializers.ChoiceField(choices=CHOICES, source="get_category_display")
pub_time = serializers.DateField()
from rest_framework.views import APIView
from rest_framework.response import Response
from app.models import Book, Publisher
from app.serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
建网站原本是网站策划师、网络程序员、网页设计师等,应用各种网络程序开发技术和网页设计技术配合操作的协同工作。成都创新互联专业提供网站建设、网站设计,网页设计,网站制作(企业站、响应式网站建设、电商门户网站)等服务,从网站深度策划、搜索引擎友好度优化到用户体验的提升,我们力求做到极致!2.3.2外键关系序列化
#serialisers.py
from django.db import models
# Create your models here.
__all__ = ["Book", "Publisher", "Author"]
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="图书名称")
CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
category = models.IntegerField(choices=CHOICES, verbose_name="图书的类别")
pub_time = models.DateField(verbose_name="图书的出版日期")
publisher = models.ForeignKey(to="Publisher", on_delete=None)
author = models.ManyToManyField(to="Author")
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "book"
class Publisher(models.Model):
title = models.CharField(max_length=32, verbose_name="出版社的名称")
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "publish"
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者的姓名")
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "author"
#views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from app.models import Book, Publisher
from app.serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
2.3.3DRF反序列化
当前端给我们发post的请求的时候~前端给我们传过来的数据~我们要进行一些校验然后保存到数据库~
这些校验以及保存工作,DRF的Serializer也给我们提供了一些方法了~~
首先~我们要写反序列化用的一些字段~有些字段要跟序列化区分开~
Serializer提供了.is_valid() 和.save()方法~~
使用write_only=True,read_only=True区别序列化字段和反序列化字段
必须重写create方法
from rest_framework import serializers
from .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)
book_obj = {
"title": "vita的使用教程",
"w_category": 1,
"pub_time": "2018-10-09",
"publisher_id": 1,
"author_list": [1, 2]
}
class BookSerializer(serializers.Serializer):
# 插入数据时id自动生成,不需要校验
id = serializers.IntegerField(required=False)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
# read_only=True只在序列化的时候使用
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
pub_time = serializers.DateField()
# write_only=True反序列化的字段,只在反序列化的时候使用,即保存数据的时候使用
w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
# 只在反序列化的时候使用,插入数据的时候,只需要插入publisher_id就可以了
publisher_id = serializers.IntegerField(write_only=True)
# 一定要加上read_only=True,否则在插入数据的时候,提示该字段必须添加
publisher = PublisherSerializer(read_only=True)
# 指明是多对多的外键关系
author = AuthorSerializer(many=True, read_only=True)
# 同样,只在反序列化,保存数据的时候使用
author_list = serializers.ListField(write_only=True)
def create(self, validated_data):
"""
反序列化的时候,一定要写create方法
:param validated_data:
:return:
"""
book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
# 多对多的创建
book.author.add(*validated_data["author_list"])
return book
#views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from app.models import Book, Publisher
from app.serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
def post(self, request):
"""
反序列化,保存数据
:param request:
:return:
"""
print(request.data)
serializer = BookSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
2.3.5获取单条数据
#urls.py
from django.contrib import admin
from django.urls import path,include
from app.views import BookView,BookEditView
urlpatterns = [
path('admin/', admin.site.urls),
path('list', BookView.as_view()),
path('retrieve/', BookEditView.as_view()),
]
#views.py
class BookEditView(APIView):
def get(self, request, id):
"""
获取单条数据的接口
:param request:
:param id:
:return:
"""
book_obj = Book.objects.filter(id=id).first()
ret = BookSerializer(book_obj)
return Response(ret.data)
2.3.6PUT请求的部分验证
# views.py
class BookEditView(APIView):
def get(self, request, id):
"""
获取单条数据的接口
:param request:
:param id:
:return:
"""
book_obj = Book.objects.filter(id=id).first()
ret = BookSerializer(book_obj)
return Response(ret.data)
def put(self, request, id):
"""
用户提交Put请求
:param request:
:param id:
:return:
"""
book_obj = Book.objects.filter(id=id).first()
# partial=True允许部分校验
serializer = BookSerializer(book_obj, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
from rest_framework import serializers
from .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)
book_obj = {
"title": "vita的使用教程",
"w_category": 1,
"pub_time": "2018-10-09",
"publisher_id": 1,
"author_list": [1, 2]
}
put_data = {
"title": "vita的使用教程2"
}
class BookSerializer(serializers.Serializer):
# 插入数据时id自动生成,不需要校验
id = serializers.IntegerField(required=False)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
# read_only=True只在序列化的时候使用
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
pub_time = serializers.DateField()
# write_only=True反序列化的字段,只在反序列化的时候使用,即保存数据的时候使用
w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
# 只在反序列化的时候使用,插入数据的时候,只需要插入publisher_id就可以了
publisher_id = serializers.IntegerField(write_only=True)
# 一定要加上read_only=True,否则在插入数据的时候,提示该字段必须添加
publisher = PublisherSerializer(read_only=True)
# 指明是多对多的外键关系
author = AuthorSerializer(many=True, read_only=True)
# 同样,只在反序列化,保存数据的时候使用
author_list = serializers.ListField(write_only=True)
def create(self, validated_data):
"""
反序列化的时候,一定要写create方法
:param validated_data:
:return:
"""
book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
# 多对多的创建
book.author.add(*validated_data["author_list"])
return book
def update(self, instance, validated_data):
"""
Put请求的方法
:param instance:
:param validated_data:
:return:
"""
#如果该字段没有,就使用原来的数据
instance.title = validated_data.get("title", instance.title)
instance.category = validated_data.get("category", instance.category)
instance.pub_time = validated_data.get("pub_time", instance.pub_time)
instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
# 多对多的处理,如果用户传了该字段,就更新
if validated_data.get("author_list"):
instance.author.set(validated_data["author_list"])
instance.save()
return instance
2.3.7DRF验证
def my_validate(value):
"""
全局验证
:param value:
:return:
"""
if "敏感信息" in value.lower():
raise serializers.ValidationError("不能含有敏感信息")
else:
return value
class BookSerializer(serializers.Serializer):
# 插入数据时id自动生成,不需要校验
id = serializers.IntegerField(required=False)
title = serializers.CharField(max_length=32, validators=[my_validate])
CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
# read_only=True只在序列化的时候使用
category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
pub_time = serializers.DateField()
# write_only=True反序列化的字段,只在反序列化的时候使用,即保存数据的时候使用
w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
# 只在反序列化的时候使用,插入数据的时候,只需要插入publisher_id就可以了
publisher_id = serializers.IntegerField(write_only=True)
# 一定要加上read_only=True,否则在插入数据的时候,提示该字段必须添加
publisher = PublisherSerializer(read_only=True)
# 指明是多对多的外键关系
author = AuthorSerializer(many=True, read_only=True)
# 同样,只在反序列化,保存数据的时候使用
author_list = serializers.ListField(write_only=True)
def create(self, validated_data):
"""
反序列化的时候,一定要写create方法
:param validated_data:
:return:
"""
book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
# 多对多的创建
book.author.add(*validated_data["author_list"])
return book
def update(self, instance, validated_data):
"""
Put请求的方法
:param instance:
:param validated_data:
:return:
"""
#如果该字段没有,就使用原来的数据
instance.title = validated_data.get("title", instance.title)
instance.category = validated_data.get("category", instance.category)
instance.pub_time = validated_data.get("pub_time", instance.pub_time)
instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
# 多对多的处理,如果用户传了该字段,就更新
if validated_data.get("author_list"):
instance.author.set(validated_data["author_list"])
instance.save()
return instance
def validate_title(self, value):
"""
单个字段的验证
:param value:
:return:
"""
if "python" not in value.lower():
raise serializers.ValidationError("标题必须含有python")
return value
def validate(self, attrs):
"""
多个字段的验证
:param attrs:
:return:
"""
if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
return attrs
else:
raise serializers.ValidationError("分类以及标题不符合要求")
2.3.8 ModelSerializer
现在我们已经清楚了Serializer的用法,会发现我们所有的序列化跟我们的模型都紧密相关~
那么,DRF也给我们提供了跟模型紧密相关的序列化器~~ModelSerializer~~
-- 它会根据模型自动生成一组字段
-- 它简单的默认实现了.update()以及.create()方法
2.3.8.1定义一个ModelSerializer序列化器
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
2.3.8.2外键关系的序列化
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
depth = 1
# depth 代表找嵌套关系的第几层
2.3.8.3自定义字段
我们可以声明一些字段来覆盖默认字段,来进行自定制~
比如我们的选择字段,默认显示的是选择的key,我们要给用户展示的是value。
class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True)
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
depth = 1
2.3.8.4meta中其他关键字参数
class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True)
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
depth = 1
read_only_fields = ["id"]
extra_kwargs = {"title": {"validators": [my_validate,]}}
2.3.8.5post以及patch请求
由于depth会让我们外键变成只读,所以我们再定义一个序列化的类,其实只要去掉depth就可以了~~
class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True)
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
read_only_fields = ["id"]
extra_kwargs = {"title": {"validators": [my_validate,]}}
2.3.8.6SerializerMethodField
外键关联的对象有很多字段我们是用不到的~都传给前端会有数据冗余~就需要我们自己去定制序列化外键对象的哪些字段~~
class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True)
user = serializers.SerializerMethodField()
publisher = serializers.SerializerMethodField()
def get_user(self, obj):
# obj是当前序列化的book对象
users_query_set = obj.user.all()
return [{"id": user_obj.pk, "name": user_obj.name} for user_obj in users_query_set]
def get_publisher(self, obj):
publisher_obj = obj.publisher
return {"id": publisher_obj.pk, "title": publisher_obj.title}
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
read_only_fields = ["id"]
extra_kwargs = {"title": {"validators": [my_validate,]}
2.3.8.7用ModelSerializer改进上面Serializer的完整版
class BookSerializer(serializers.ModelSerializer):
dis_chapter = serializers.SerializerMethodField(read_only=True)
users = serializers.SerializerMethodField(read_only=True)
publishers = serializers.SerializerMethodField(read_only=True)
def get_users(self, obj):
# obj是当前序列化的book对象
users_query_set = obj.user.all()
return [{"id": user_obj.pk, "name": user_obj.name} for user_obj in users_query_set]
def get_publishers(self, obj):
publisher_obj = obj.publisher
return {"id": publisher_obj.pk, "title": publisher_obj.title}
def get_dis_chapter(self, obj):
return obj.get_chapter_display()
class Meta:
model = Book
# fields = "__all__"
# 字段是有序的
fields = ["id", "title","dis_chapter", "pub_time", "publishers", "users","chapter", "user", "publisher"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
read_only_fields = ["id", "dis_chapter", "users", "publishers"]
extra_kwargs = {"title": {"validators": [my_validate,]}, "user": {"write_only": True}, "publisher": {"write_only": True},
"chapter": {"write_only": True}}
另外有需要云服务器可以了解下创新互联cdcxhl.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
分享名称:restful-framwork-创新互联
本文来源:http://myzitong.com/article/iigep.html