RESTful规范(一)

时间:2021-05-06 21:53:31

一、学习restframework之前准备

1、json格式若想展示中文,需要ensure_ascii=False

import json

dic={'name':'你好'}
print(json.dumps(dic,ensure_ascii=False))

2、不基于restframework也可以通过django来做符合restframework的规范接口设计,Jsonresponse,若想在json展示中文,如下

def books(request):

    ll=[{'name':'python全站开发','price':},{'name':'linux','price':}]

    # return HttpResponse(json.dumps(ll))
return JsonResponse(ll,safe=False,json_dumps_params={'ensure_ascii':False})

3、原声cbv执行流程

url(r'^books/$', views.Book.as_view()),

原声cbv执行流程---》as_view----》dispatch---》相应到具体的函数
from django.views import View
class Book(View):
def get(self,reuquest):
# reuquest.method
return HttpResponse('get')
def post(self,request):
return HttpResponse('post')

3、分析restframework

一 restfu(规范)
是什么:
-面向资源编程
-getBooklist:获取图书列表
-符合规范的:books
规范:
-method:get----》books----》取到所有的书 post———》books---》新增图书 put/patch--》books/id---》修改图书 delete---》books/id---》删除图书
-https://api.example.com/v1/zoos?limit=10
- 二 drf
安装(app):pip3 install djangorestframework
-基于drf写resful的接口,得写CBV
-request对象,源码分析
-APIView源码分析

二、restframework使用

1、POST没法解析json格式,可以在body里取值出来序列化反序列化操作转成字典,目前drf可以在前台提交post后台取值的话用data,

from rest_framework.views import APIView

class Book(APIView):
def get(self,request):
# 拿原来的request对象
# request._request
# print(request.method)
# print(request._request.method)
# request.POST
# request.method
return HttpResponse('get')
def post(self,request):
print(request.method)
print(request._request.method)
print(request.POST) # 用apiview之后,再取数据,从request.data
print(request.data)
return HttpResponse('post')

2、用Postman模拟发http请求,网上直接下载,data可以类似于解析器,解析form-data,urlencoded,json格式,而django只能解析form-data,urlencoded两种格式

三、序列化组件

1、从数据库取出来的都是qs类型,里面套了一个一个对象,要传到前台去必须要json格式,符合drf规范的第一种方式

数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'resful',
'USER':'root',
'PASSWORD':'',
'HOST':'127.0.0.1',
'PORT':,
}
}

models取值为qureryset类型,

from app01 import models
序列化组建
第一种方式
class Book(APIView):
def get(self,request):
response={'status':,'msg':None}
books=models.Book.objects.all()
# ll=[]
# for book in books:
# ll.append({'name':book.name,''})
ll=[ {'name':book.name,'price':book.price} for book in books]
response['msg']='查询成功'
response['data']=ll
return JsonResponse(response,safe=False) # return HttpResponse('get')
def post(self,request): return HttpResponse('post')

2、第二种方式,用django子自带序列化组件serializers(Django内置的serializers(把对象序列化成json字符串),但是有个缺点不能定制化

from django.core import serializers

class Book(APIView):
def get(self,request):
# response={'status':,'msg':None}
books = models.Book.objects.all()
ret = serializers.serialize("json", books)
return HttpResponse(ret) # return HttpResponse('get')
def post(self,request): return HttpResponse('post')

3、用drf自带的组件,建议的话新建个py在APP下,方便解耦,如myserial.py,为符合drf格式,里面新建个response类,见下

    - 导入:from rest_framework import serializers
- 写一个类(名字任意),继承serializers.Serializer
class BookSer(serializers.Serializer):
nid=serializers.IntegerField()
name3=serializers.CharField(source='name')
price=serializers.CharField()
# publish_date = serializers.DateField()
publish_date = serializers.CharField()
# publish=serializers.CharField(source='publish.email')
publish=serializers.CharField(source='publish.name')
xxx=serializers.CharField(source='test')
- 如果不指定source,字段名,必须跟数据库列名一致
- source--》既可以指定数据属性,又可以指定方法属性,可以写(publish.name)
- 使用:
-查询出要序列化的数据:books = models.Book.objects.all()
-ret=myserial.BookSer(books,many=True)-----》多条(queryset对象),必须指定many=True
-ret=myserial.BookSer(books,many=False)-----》一条(Book对象),必须指定many=False
- aa=serializers.SerializerMethodField()
-必须配套一个方法(get_aa(self,obj)),方法返回结果,会赋给aa
-在方法内部,可以继续用序列化组件

myserial.py

from rest_framework import serializers

class BookSer(serializers.Serializer):
nid=serializers.IntegerField()
name3=serializers.CharField(source='name')
price=serializers.CharField()
# publish_date = serializers.DateField()
publish_date = serializers.CharField()
# publish=serializers.CharField(source='publish.email')
publish=serializers.CharField(source='publish.name')
xxx=serializers.CharField(source='test')
# authors=serializers.CharField(source='authors.all')
# SerializerMethodField,可以写一个方法方法名叫:get_字段名字,方法返回值,会赋给authors
aa=serializers.SerializerMethodField()
# def get_authors(self,obj):
# authors=obj.authors.all()
# # ll=[ author.name for author in authors]
# ll=[ {'name':author.name,'age':author.age} for author in authors]
# return ll
def get_aa(self, obj):
authors = obj.authors.all()
# ll=[ author.name for author in authors]
ser=AuthorSer(authors,many=True)
return ser.data

models.py

class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=)
price = models.DecimalField(max_digits=, decimal_places=)
publish_date = models.DateField(auto_now_add=True) publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
authors=models.ManyToManyField(to='Author') def test(self):
return 'ttttttt'
def __str__(self):
return self.name

使用,为符合drf格式,里面新建个response类,@property让类方法变属性,不需要(),直接点+属性就ok了

class MyResponse():
def __init__(self):
self.status =
self.msg = None @property
def get_dic(self):
return self.__dict__from app01 import myserial
class Book(APIView):
queryset=models.Book.objects.all()
serializer_class=myserial.BookSer
def get(self,request):
response=MyResponse()
# 多条
# books = models.Book.objects.all()
# ret=myserial.BookSer(books,many=True)
# 一条
book = self.queryset
# ret = myserial.BookSer(book, many=False)
ret = self.serializer_class(instance=book, many=True)
response.msg='查询成功'
response.data=ret.data
return JsonResponse(response.get_dic,safe=False) # return HttpResponse('get')
def post(self,request):
     # return HttpResponse('post')

4、若要进行多对多的查询,book和author,可以用SerializerMethodField方法

   - aa=serializers.SerializerMethodField()
-必须配套一个方法(get_aa(self,obj)),方法返回结果,会赋给aa
-在方法内部,可以继续用序列化组件

如下

class BookSer(serializers.Serializer):
nid=serializers.IntegerField()
name3=serializers.CharField(source='name')
price=serializers.CharField()
# publish_date = serializers.DateField()
publish_date = serializers.CharField()
# publish=serializers.CharField(source='publish.email')
publish=serializers.CharField(source='publish.name')
xxx=serializers.CharField(source='test')
# authors=serializers.CharField(source='authors.all')
# SerializerMethodField,可以写一个方法方法名叫:get_字段名字,方法返回值,会赋给authors
aa=serializers.SerializerMethodField()
# def get_authors(self,obj):
# authors=obj.authors.all()
# # ll=[ author.name for author in authors]
# ll=[ {'name':author.name,'age':author.age} for author in authors]
# return ll
def get_aa(self, obj):
authors = obj.authors.all()
# ll=[ author.name for author in authors]
ser=AuthorSer(authors,many=True)
return ser.data class AuthorSer(serializers.Serializer):
id=serializers.IntegerField(source='nid')
age=serializers.CharField()
name=serializers.CharField()

四 序列化组件之serializers.ModelSerializer

    -用法同Serializer
-不同点:
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列号的表模型是book
model=models.Book
fields='__all__'
exclude=['nid']
depth=

例子如下

from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列号的表模型是book
model=models.Book
# 把所有字段都序列化
# fields='__all__'
# 可以传列表,指定取几个
# fields=['name','authors','publish']
# 除了nid都查
exclude=['authors']
#fields和exclude不能同时用
# depth指定深度,个人建议最多用3
# depth=

五 序列化组件的字段校验和反序列化功能

序列化组件是将对象序列化成字典,但是前台post提交的json数据需要转成字典,再反序列化成对象,最后save()方法才能保存在数据里,需要反序列功能

    -只有:ModelSerializer,能直接保存
- def post(self,request):
print(request.data)
#生成一个序列化对象
ser=myserial.BookSer(data=request.data)
#判断字段是否校验通过
if ser.is_valid():
#通过,直接保存
ser.save()
else:
#错误信息
print(ser.errors) return HttpResponse('post')
from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列号的表模型是book
model=models.Book
exclude=['authors']

如下

 def post(self,request):
# print(request.data)
ser=myserial.BookSer(data=request.data)
if ser.is_valid():
ser.save()
return HttpResponse('成功')
else:
print(ser.errors) return JsonResponse(ser.errors)

六 序列化组件局部校验和全局校验

    -局部校验
name=serializers.CharField()
def validate_name(self,value):
if value.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return value
-全局校验
def validate(self,value):
print(type(value))
print(value)
name=value.get('name')
price=value.get('price')
if name!=price:
raise ValidationError('书名和价格不相等')
else: return value

如下

from rest_framework.exceptions import ValidationError
from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列号的表模型是book
model=models.Book
# 把所有字段都序列化
# fields='__all__'
# 可以传列表,指定取几个
# fields=['name','authors','publish']
# 除了nid都查
exclude=['authors']
#fields和exclude不能同时用
# depth指定深度,个人建议最多用3
# depth=
局部校验
name=serializers.CharField(error_messages={'required':'该字段必填'})
def validate_name(self,value):
if value.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return value
全局校验
def validate(self,value):
print(type(value))
print(value)
name=value.get('name')
price=value.get('price')
if name!=price:
raise ValidationError('书名和价格不相等')
else: return value

views,主要验证前台post提交数据的局部和全局验证

from app01 import myserial
class Book(APIView):
queryset=models.Book.objects.all()
serializer_class=myserial.BookSer
def get(self,request):
response=MyResponse()
# 多条
# books = models.Book.objects.all()
# ret=myserial.BookSer(books,many=True)
# 一条
book = self.queryset
# ret = myserial.BookSer(book, many=False)
ret = self.serializer_class(instance=book, many=True)
response.msg='查询成功'
response.data=ret.data
return JsonResponse(response.get_dic,safe=False) # return HttpResponse('get')
def post(self,request):
# print(request.data)
ser=myserial.BookSer(data=request.data)
if ser.is_valid():
ser.save()
return HttpResponse('成功')
else:
print(ser.errors) return JsonResponse(ser.errors)

七、符合drf的视图类基本写法

1、views.py


class MyResponse():
def __init__(self):
self.status = 100
self.msg = None @property
def get_dic(self):
return self.__dict__
class BookDetail(APIView):
def get(self,request,id):
response=MyResponse()
ret=models.Book.objects.filter(pk=id).first()
ser=myserial.BookSer(instance=ret,many=False)
response.msg='查询成功'
response.data=ser.data
return JsonResponse(response.get_dic,safe=False) def put(self,request,id):
# 修改
response=MyResponse()
book=models.Book.objects.filter(pk=id).first()
ser=myserial.BookSer(instance=book,data=request.data)
if ser.is_valid():
# 可以新增,可以修改
ser.save()
print(ser.data)
print(type(ser.instance))
response.msg='修改成功'
response.data=ser.data else:
response.msg = '修改失败'
response.status =
response.data=ser.errors
return JsonResponse(response.get_dic,safe=False) def delete(self,request,id):
ret=models.Book.objects.filter(pk=id).delete()
return HttpResponse('删除成功')

2、序列化组件

url(r'^books/(?P<pk>\d+)/', views.BookDetail.as_view()),
from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列号的表模型是book
model=models.Book
exclude=['authors']