RESTful规范
你的项目接口是按照RESTful规范写的,那么它就是RESTful API。
设计指南:
用HTTP协议的四个请求方法表示四个动作。
GET:查询/获取资源
POST:创建资源
PUT:更新
DELETE:删除
十个设计规范:
Https
版本号
api
URL尽量不要用动词
错误提示
状态码
1xx
2xx
3xx
4xx
502:网关不可用
503:服务不可用
504:网关超时
505:版本不支持
超链接表示表的关系
过滤信息
分页
浏览器的同源策略
什么是同源:
域名/ip + 端口 + 协议
http协议默认端口:80
https协议默认端口:443
浏览器对于非同源的请求会拒绝接受响应信息。
前后端分离的项目一般都会涉及到跨域问题
JSONP跨域(之前的解决方案)
不足:
只能GET请求
前端和后端都要支持
原理:
利用的就是浏览器对加载静态资源不做限制,比如
jQuery版JSONP
$.getJSON("http://127.0.0.1:8000/index/?callback=?", function(res){
console.log(res);
})
CORS跨域
简单请求和非简单请求
简单请求同时满足两大类条件:
1请求方法:
HEAD、GET、POST
2.请求头
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
如果发送的是PUT或DELETE请求就是费简单请求
再比如发送的是 Content-Type:application/json也是非简单请求
简单请求的处理方案:
在响应头加一个Access-Control-Allow-Origin * --》 允许任何源给我发跨域请求
在响应头加一个Access-Control-Allow-Origin 127.0.0.1:8000 --》只允许 127.0.0.1:8000 给我发跨域请求
非简单请求:
浏览器会提前发一个 OPTIONS的预检请求
在响应头加一个Access-Control-Allow-Methods:‘PUT, DELETE’ --》允许浏览器给我发PUT和DELETE的跨域请求
在响应头加一个Access-Control-Allow-Headers: ‘Content-Type’ --》 允许浏览器给我发请求头中修改Content-Type字段
使用django-cors-headers包
pip install django-cors-headers
在中间件中注册
MIDDLEWARE = [
‘corsheaders.middleware.CorsMiddleware’, # 添加中间件
‘django.middleware.security.SecurityMiddleware’,
‘django.contrib.sessions.middleware.SessionMiddleware’,
‘django.middleware.common.CommonMiddleware’,
# ‘django.middleware.csrf.CsrfViewMiddleware’,
‘django.contrib.auth.middleware.AuthenticationMiddleware’,
‘django.contrib.messages.middleware.MessageMiddleware’,
‘django.middleware.clickjacking.XFrameOptionsMiddleware’,
]
在Django的settings.py中配置:
CORS_ORIGIN_ALLOW_ALL = True # 允许任何网站都来发跨域请求
1
配置可跨域访问的白名单:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
# ‘<YOUR_DOMAIN>[:PORT]’,
‘127.0.0.1:8080’
)
Django REST framework
1.安装:
pip install djangorestframework
2.使用:
注册app (不是必须)注册之后能够在页面的视图中看到
INSTALLED_APPS = [
#…
‘corsheaders’,
‘rest_framework’
]
常规的django操作
1创建超级用户
python manage.py createsuperuser
Username (leave blank to use ‘administrator’): root
Email address:直接回车表示不填写
Password:密码
Password (again):密码
Superuser created successfully.
2修改时区和后台显示语言
LANGUAGE_CODE = ‘en-us’
LANGUAGE_CODE = ‘zh-hans’
TIME_ZONE = ‘UTC’
TIME_ZONE = ‘Asia/Shanghai’
1
2
3.注册model到admin中 以便于后台管理
from django.contrib import admin
from myJsonApi import models
admin.site.register(models.Book)
admin.site.register(models.Author)
admin.site.register(models.Publisher)
导入APIView from rest_framewor.views import APIView, CBV继承它
1 自己写一个序列化的工具类 BookSerializer
from rest_framework import serializers
from myJsonApi import models
class AuthorSerializers(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
class PublisherSerializers(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
相当于django的form和ModelForm
class BookSerializers(serializers.Serializer):
# required=False指的是不是必填项(保存数据时数据库自动生成id的时候)
id = serializers.IntegerField(required=False)
# 对长度进行校验
title = serializers.CharField(max_length=32)
# 等号前面填写的就是数据库中写的字段名
pub_date = serializers.DateField()
# sourse="get_category_display"是拿到数据库中存的展示的值
# 例如 CHOICES为1代表的值时Python
# CHOICES = ((1, ‘Python’), (2, ‘Go’), (3, ‘Linux’))
category = serializers.CharField(source=“get_category_display”, read_only=True)
post_category = serializers.CharField(write_only=True)
# read_only=True是给前端发数据的时候用的
# 调用前面定义好的类来处理出版社,(外键)
publisher = PublisherSerializers(read_only=True)
post_publisher = serializers.IntegerField(write_only=True)
# many=True,代表的是可以展示多个
# 调用前面定义好的类来处理作者,(多对多字段)
author = AuthorSerializers(many=True, read_only=True)
# write_only = True是在后端收到前端数据的时候用的
# 意味着前端传值的时候关键字变为自己定义的post_author
# ListField可以传数组即多个值
post_author = serializers.ListField(write_only=True)
1.2 在视图中调用
from rest_framework.views import APIView
from rest_framework.response import Response
from myJsonApi.Serializers import BookSerializers
class BookList(APIView):
def get(self, request):
# 查询出数据
books = models.Book.objects.all()
# 进行序列化
books_json = BookSerializers(books, many=True)
# 返回json格式的数据
return Response(books_json.data)
post新增数据
在BookSerializers中
def create(self, validated_data):
validated_data是校验过的数据
book_obj = models.Book.objects.create(
title=validated_data.get(‘title’),
pub_date=validated_data[‘pub_date’],
category=validated_data[‘post_category’],
publisher_id=validated_data[‘post_publisher’], # 1
)
book_obj.authors.set(validated_data[‘post_authors’])
return book_obj
在视图中class BookList(APIView):
def post(self, request):
获取数据(因为APIView对request进行增强,将数据赋值到了request.data)
对数据进行有效性校验
ser_obj = BookSerializers(data=request.data)
if ser_obj.is_valid():
.save()# 调用的是BookSerializer类中的create方法,需要自己去实现
拿到序列化的数据去数据库创建新记录
ser_obj.save()
else:
校验失败则返回错误原因
return Response(ser_obj.errors)
return Response(“ok”)
对单本书的增删改查
在ModelSerializers中
“”"
专门用来做序列化的工具类
“”"
from rest_framework import serializers
from bms import models
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField()
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField()
class BookModelSerializer(serializers.ModelSerializer):
# SerializerMethodField 会自动去找 get_字段名 的方法执行
category_info = serializers.SerializerMethodField(read_only=True)
publisher_info = serializers.SerializerMethodField(read_only=True)
authors_info = serializers.SerializerMethodField(read_only=True)
def get_category_info(self, book_obj):
# obj ==》 当前被序列化的那个书籍对象
return book_obj.get_category_display()
def get_publisher_info(self, book_obj):
# book_obj.pulisher ==> 得到和我这本书关联的出版社对象
# return {
# "id": book_obj.publiser.id,
# "name": book_obj.publiser.name
# }
# ser_obj = PublisherSerializer(book_obj.publisher)
# return ser_obj.data
return PublisherSerializer(book_obj.publisher).data
def get_authors_info(self, book_obj):
# 这里的.all()和 many=True是指有多个作者的时候这样写
return AuthorSerializer(book_obj.authors.all(), many=True).data
class Meta:
model = models.Book
fields = "__all__"
# depth = 1 # 所有有关系的字段都变成 read_only
# exclude = [] # 排除某个字段
extra_kwargs = { # 每个字段的一些额外参数
'publisher': {'write_only': True},
'authors': {'write_only': True},
'category': {'write_only': True},
}
在视图中使用BookModelSerializer
from 你的app.你的py文件写的名字 import BookModelSerializer
class BookDetailView(APIView):
“”“这是书籍详情相关的接口 支持:GET/PUT/DELETE”""
def get(self, request, pk):
“”“获取具体某本书的信息”""
# 1. 根据pk去查询具体的那本书籍对象
book_obj = models.Book.objects.filter(pk=pk).first()
if book_obj:
# 2. 将书籍对象 序列化成 json格式的数据
ser_obj = BookModelSerializer(book_obj)
# 3. 返回响应
return Response(ser_obj.data)
else:
return Response(“无效的书籍id”)
def put(self, request, pk):
"""修改具体某一本书"""
# 1. 根据pk去查询具体的那本书籍对象
book_obj = models.Book.objects.filter(pk=pk).first()
if book_obj:
# 2. 获取用户 发送过来的数据并且更新对象
ser_obj = BookModelSerializer(instance=book_obj, data=request.data, partial=True) # form组件中也有类似的实现
if ser_obj.is_valid():
# 3. 保存并返回修改后的数据
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
else:
return Response("无效的书籍id")
def delete(self, request, pk):
"""删除具体某一本书"""
# 1. 根据pk去查询具体的那本书籍对象
book_obj = models.Book.objects.filter(pk=pk)
if book_obj:
# 删除书籍对象
book_obj.delete()
return Response("删除成功")
else:
return Response("无效的书籍id")