一、序列化组件之HyperlinkedIdentityField
HyperlinkedIdentityField可以通过反向解析向前台返回一个链接
url(r'^Books/(?P<id>\d+)', views.BooksDetail.as_view(),name='test'),
# 传三个参数
# view_name='test':路由名字,用来反向解析
# lookup_field='publish_id':要反向解析的参数值
# lookup_url_kwarg='id':有名分组的名字
url = serializers.HyperlinkedIdentityField(view_name='test', lookup_field='publish_id',lookup_url_kwarg='id')
class Books(APIView):
def get(self, request):
response = {'status': 200, 'msg': '查询成功', 'data': None}
books = models.Book.objects.all()
# context={'request':request}是必写的
ret = BooksSerializers(books, many=True,context={'request':request})
response['data'] = ret.data
return JsonResponse(response, safe=False)
# 返回结果
{
"status": 200,
"msg": "查询成功",
"data": [
{
"id": 1,
"url": "http://127.0.0.1:8000/Books/1",
"name": "红楼梦",
"price": "42.21",
"publish": 1,
"authors": [
1,
2
]
},
{
"id": 3,
"url": "http://127.0.0.1:8000/Books/2",
"name": "西游记",
"price": "12.32",
"publish": 2,
"authors": [
2
]
}
]
}
# url": "http://127.0.0.1:8000/Books/1"
# context={'request':request}:得到了域名http://127.0.0.1:8000
# view_name:得到了Books/(?P<id>\d+)
# lookup_field 和lookup_url_kwarg:得到了1
# 把这三个拼接起来就成了一条路由http://127.0.0.1:8000/Books/1
二、序列化组件之数据校验
1.基本使用
class BooksSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
# 添加数据
def post(self, request):
response = {'status': 200, 'msg': '添加成功', 'data': None}
# 反序列化把request.data中的JSON格式的数据传入data中
ret = BooksSerializers(data = request.data)
# is_valid 对反序列化后的数据进行校验
if ret.is_valid():
# 对校验成功的数据保存
ret.save()
response['data'] = ret.data
else:
response['status'] = 201
# errors:错误信息
response['data'] = ret.errors
response['msg'] = '添加失败'
return JsonResponse(response, safe=False)
# 如果是更新数据
def put(self, request, id):
response = {'status': 200, 'msg': '修改成功', 'data': None}
books = models.Book.objects.filter(pk=id).first()
if books:
# 不传instance,调save(),往数据库新增数据
# 传instance,调save(),修改数据
# BooksSerializers(data=request.data.instance='要更新的对象')
ret = BooksSerializers(data=request.data,instance=books)
if ret.is_valid():
ret.save()
response['data'] = ret.data
else:
response['status'] = 201
response['data'] = ret.errors
response['msg'] = '修改失败'
else:
response['status'] = 201
response['msg'] = '修改对象不存在'
return JsonResponse(response, safe=False)
2.自定义错误信息
class BooksSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
# 类似forms组件
name = serializers.CharField(max_length=10, min_length=3, error_messages={'max_length': '最长为10','min_length': '最短为3','required':'不能为空'})
3.局部钩子以及全局钩子
# 局部钩子
# validate_字段名
def validate_name(self,value):
if value.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return value
# 全局钩子
# 只有通过字段校验才会判断全局钩子
def validate(self, value):
# value是通过校验的数据
print(value)
name = value.get('name')
price = value.get('price')
if name and price:
if str(name) == str(price):
# 通过判断返回value
return value
else:
# 没通过就报错
raise ValidationError('名字跟价格不相等')
return value
# 全局钩子error
# non_field_errors:[错误信息]
三、认证组件简单使用
# 模型层
class User(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
class UserToken(models.Model):
user = models.OneToOneField(to='User')
token = models.CharField(max_length=64)
#mySer.py
from rest_framework.exceptions import APIException
class Auth():
def authenticate(self,request):
# 包装后的request对象,请求来的所有东西都能拿出来
token = request.GET.get('token')
ret = models.UserToken.objects.filter(token=token).first()
# 如果有值,说明登录过了,而且带的随机字符串也是正确的
# 如果认证通过,需要返回东西,如果认证不通过,要抛异常
if ret:
return None
else:
# 如果没有值,抛异常
raise APIException('您没有登录')
from app01.mySer import *
import uuid
# 登陆视图
class Login(APIView):
def post(self, request):
response = {'status': 200, 'msg': '登录成功'}
name = request.data.get('name')
pwd = request.data.get('pwd')
user = models.User.objects.filter(name=name, pwd=pwd).first()
if user:
token = uuid.uuid4()
# 登陆成功后,存入token表
models.UserToken.objects.create(token=token, user=user)
response['token'] = token
else:
response['status'] = 201
response['msg'] = '添加失败'
return JsonResponse(response, safe=False)
class Books(APIView):
# 登录后才能操作,在所需的视图里局部使用
authentication_classes=[Auth,]
def get(self, request):
.......
def post(self, request):
.......
class BooksDetail(APIView):
authentication_classes = [Auth, ]
def get(self, request):
.......
def post(self, request):
.......
源码分析
# 第一步
# APIView类
def dispatch(self, request, *args, **kwargs):
........
# 重点是这个,这是认证、频率相关的
self.initial(request, *args, **kwargs)
........
# 第二步
# APIView类
def initial(self, request, *args, **kwargs):
........
# 这个就是认证
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
# 第三步
# APIView类
def perform_authentication(self, request):
# 这个request是已经封装好后的Request的对象
request.user
# 第四步
# Request类
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
# 第五步
# Request类
def _authenticate(self):
# 从下面回到这里,就可以知道
# self.authenticators=authentication_classes
# 拿上面的例子举例
# self.authenticators=[Auth, ];authenticator就是Auth
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
# 注意:authenticator.authenticate(self)中的self,由于是在Request类里,所以这个self就是Request实例化的对象request;
# 所以:authenticator.authenticate(self)=Auth.authenticate(self,request)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
# self.authenticators的来历
# APIView类
# self.authenticators 是Request实例化的时候传进来的参数self.get_authenticators()
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# self.get_authenticators()的来历
# APIView类
def get_authenticators(self):
# self.authentication_classes
# 从子类找验证类:authentication_classes = [Auth, ]
# 从父类APIView里找验证类:authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
# 找到之后,循环并加上()执行
return [auth() for auth in self.authentication_classes]