Django REST View&Serializer

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的模型类对象。
其他几个方法,应该都直接能看懂什么含义。

你可能感兴趣的:(Django REST View&Serializer)