DRF 的GenericAPIView要和Serializer一起使用。
Serializer
整个DRF都提供了很多方法提供覆写,相当于一个钩子。
Serializer的主要功能是:
- 把用户请求过来的数据
{"name": "zhangsan", "pwd": "123"}
(也可以根据url)转化为一个Django模型类对象。 - 把用户需要查询的数据,得到模型类对象,返回Json格式
{[{"name": "zhangsan"}, {"name": "lisi"}]}
的响应数据。
主要大功能是这两个,但是,更多小细节才能写好代码。
下面看几个例子:
class LoginUserSerializer(ModelSerializer):
email = serializers.EmailField(source='fk_email.email_address')
# email_type = serializers.IntegerField(source='get_fk_email.email_type_display')
email_type = serializers.SerializerMethodField(read_only=True) # 加括号
def validate_name(self, name):
if name == 'zhangsan':
raise serializers.ValidationError("你的名字太low了")
return name
def validate_password(self, password):
if len(password) < 4:
raise serializers.ValidationError("你的密码太短了")
return password
def get_email_type(self, obj):
print('obj', obj)
return obj.fk_email.email_type
def get_email(self, email):
return Email.objects.create(email_address=email)
def update(self, instance, validated_data):
pass
def create(self, validated_data):
print("create from serializer")
print(validated_data)
email_obj = Email.objects.create(validated_data['fk_email']['email_address'], 1)
user_obj = LoginUser.objects.create(name=validated_data['name'], password=validated_data['password'],
address=validated_data['address'], fk_email=email_obj)
print("create end serializer")
return user_obj
class Meta:
model = LoginUser
# fields = '__all__'
exclude = ['fk_email']
# depth = 0 # 0代表只获取fk_email id
继承自ModelSerializer,设置Meta
就可以指定改Serializer对应的模型类是哪个。
- 如果你想新定义要提交或者要返回的数据字段。添加类属性即可。参考上面的代码。
- 如果你写的字段和模型类重复,那么就是覆盖操作。
- 如果你要模型类有嵌套。你可以设置
depth
。 - 如果你要自定义最后模型类是如何创建更新,复写
create、update
。 - 如果你要自定义一个字段,要逻辑处理,使用
SerializerMethodField()
, 并且函数名为get_
打头,会传入模型类对象。 - 如果你想要校验所有字段,重写
validate(self, attrs)
,attrs
是字典格式,用户提交的数据。 - validate返回的attrs会给模型类当作参数创建对象,你可以修改这个attrs。
校验不通过:
raise serializers.ValidationError("你的密码太短了")
- 如果你想校验单个字段,写一个
validate_xxx(self, xxx_value)
。 -
read_only
只在返回数据给用户的时候生效。
还有一个例子:
from rest_framework.serializers import Serializer, ModelSerializer
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
User = get_user_model()
class UserDetailSerializer(ModelSerializer):
# ids = serializers.SerializerMethodField(read_only=True)
class Meta:
model = User
fields = ("name", "gender", "birthday", "email","mobile", 'id')
# def get_ids(self, obj):
# return obj.pk
class UserRegSerializer(ModelSerializer):
# 验证用户名是否存在
username = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False,
validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")])
# 输入密码的时候不显示明文
password = serializers.CharField(
style={'input_type': 'password'}, label='password', write_only=True
)
def validate(self, attrs):
print("attrs: ", attrs)
return super().validate(attrs)
def create(self, validated_data):
print(validated_data)
validated_data['name']=validated_data['username']
return super(UserRegSerializer, self).create(validated_data)
class Meta:
model = User
fields = ('username', 'password')
由于DRF依赖于Django的User模型。所以,自己的用户模型需要继承自AbstractUser
,你还要设置:
# 配置用户
AUTH_USER_MODEL = 'userapp.UserProfile'
最后一个例子:
# users/serializers.py
__author__ = 'derek'
import re
from datetime import datetime, timedelta
from MxShop.settings import REGEX_MOBILE
from users.models import VerifyCode
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from django.contrib.auth import get_user_model
User = get_user_model()
class SmsSerializer(serializers.Serializer):
'''
短信验证码
'''
mobile = serializers.CharField(max_length=11)
#函数名必须:validate + 验证字段名
def validate_mobile(self, mobile):
"""
手机号码验证
"""
# 是否已经注册
if User.objects.filter(mobile=mobile).count():
raise serializers.ValidationError("用户已经存在")
# 是否合法
if not re.match(REGEX_MOBILE, mobile):
raise serializers.ValidationError("手机号码非法")
# 验证码发送频率
#60s内只能发送一次
one_mintes_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)
if VerifyCode.objects.filter(add_time__gt=one_mintes_ago, mobile=mobile).count():
raise serializers.ValidationError("距离上一次发送未超过60s")
return mobile
class UserDetailSerializer(serializers.ModelSerializer):
"""
用户详情
"""
class Meta:
model = User
fields = ("name", "gender", "birthday", "email","mobile")
class UserRegSerializer(serializers.ModelSerializer):
'''
用户注册
'''
#UserProfile中没有code字段,这里需要自定义一个code字段
code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4,label='验证码',
error_messages={
"blank": "请输入验证码",
"required": "请输入验证码",
"max_length": "验证码格式错误",
"min_length": "验证码格式错误"
},
help_text="验证码")
#验证用户名是否存在
username = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False,
validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")])
#输入密码的时候不显示明文
password = serializers.CharField(
style={'input_type': 'password'},label=True,write_only=True
)
# #密码加密保存
# def create(self, validated_data):
# user = super(UserRegSerializer, self).create(validated_data=validated_data)
# user.set_password(validated_data["password"])
# user.save()
# return user
#验证code
def validate_code(self, code):
# 用户注册,已post方式提交注册信息,post的数据都保存在initial_data里面
#username就是用户注册的手机号,验证码按添加时间倒序排序,为了后面验证过期,错误等
verify_records = VerifyCode.objects.filter(mobile=self.initial_data["username"]).order_by("-add_time")
if verify_records:
# 最近的一个验证码
last_record = verify_records[0]
# 有效期为五分钟。
five_mintes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
if five_mintes_ago > last_record.add_time:
raise serializers.ValidationError("验证码过期")
if last_record.code != code:
raise serializers.ValidationError("验证码错误")
else:
raise serializers.ValidationError("验证码错误")
# 所有字段。attrs是字段验证合法之后返回的总的dict
def validate(self, attrs):
#前端没有传mobile值到后端,这里添加进来
attrs["mobile"] = attrs["username"]
#code是自己添加得,数据库中并没有这个字段,验证完就删除掉
del attrs["code"]
return attrs
class Meta:
model = User
fields = ('username','code','mobile','password')
View
View这部分在上几个文章已经说过了。这里只做补充。
看例子:
from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins
from rest_framework import permissions
from userapp.serializer import UserDetailSerializer
from django.contrib.auth import get_user_model
from userapp.serializer import UserRegSerializer
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework import status
from rest_framework.serializers import Serializer
from rest_framework.authentication import SessionAuthentication, BaseAuthentication
from rest_framework.permissions import IsAuthenticated, AllowAny # 默认的权限是allow any
from django.views.decorators.csrf import csrf_exempt
from django.middleware.csrf import CsrfViewMiddleware
User = get_user_model()
class UsersViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.ListModelMixin, # 测试使用
mixins.UpdateModelMixin,
GenericViewSet):
serializer_class = UserDetailSerializer
queryset = User.objects.all()
def create(self, request: Request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = self.perform_create(serializer)
re_dict = serializer.data
re_dict["name"] = user.name if user.name else user.username
headers = self.get_success_headers(serializer.data)
# 测试get_obj
# print('get_obj', self.get_object())
return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)
def get_permissions(self):
if self.action == 'retrieve': # 获取,需要权限
return [permissions.IsAuthenticated()] # 返回实例对象
elif self.action == 'create': # 创建 不需要权限
return [] # 返回空即可
return []
def get_serializer_class(self):
if self.action == 'retrieve':
return UserDetailSerializer
elif self.action == 'create':
return UserRegSerializer
return UserDetailSerializer
def perform_create(self, serializer)->Serializer:
return serializer.save()
这里说一下get_object
干嘛用的,get_object
里面先根据过滤器(默认为空)得到ModeClass.obects.all()
再过滤后的数据,然后判断你url上的pk值,也就是localhost:8000/users/1/
, 1就是pk。根据pk返回一个模型类对象,因为pk是唯一标识。所以,这个方法是用来返回指定url的pk的模型类对象。
其他几个方法,应该都直接能看懂什么含义。