drf–验证前端传递过来的数据
-
前端传来的数据先走mixins,然后进行验证,验证通过后,就会调用ModelSerializer的create或者update方法,如果继承的是Serializer,就需要自己重载Serializer中的create或者update方法,或者修改mixins的create等方法的逻辑进行保存。
-
ModelSerializer和ModelForm一样, 验证都是在ModelSerializer和ModelForm里验证
-
views
from django.contrib.auth import get_user_model from rest_framework.mixins import CreateModelMixin from rest_framework import viewsets from .serializers import UserRegSerializer # 获取用户模型类 UserProfile = get_user_model() class UserViewSet(CreateModelMixin, viewsets.GenericViewSet): """ 用户注册 """ # 会调用ModelSerializer的create或者update方法, # 如果继承的是Serializer,就需要自己重载Serializer中的create或者update方法,或者修改mixins的create等方法的逻辑进行保存 serializer_class = UserRegSerializer queryset = UserProfile.objects.all()
-
serializer
from datetime import datetime from datetime import timedelta from rest_framework import serializers # 导入rest_framework的验证器 from rest_framework.validators import UniqueValidator from django.contrib.auth import get_user_model from .models import VerifyCode UserProfile = get_user_model() class UserRegSerializer(serializers.ModelSerializer): # 因为UserProfile里面没有code字段, 所以我们要加个code字段 # help_text = "验证码" 提示是验证码 # label 一个简短的文本字符串,可用作HTML表单字段或其他描述性元素中字段的名称。 # write_only 将其设置True为确保在更新或创建实例时可以使用该字段,但在序列化表示时不包括该字段。 默认为 False code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label="验证码", error_messages={ # 设置每种错误的错误提示 # blank是指为空 "blank": "请输入验证码", # required是键都没有才会报这个错误 "required": "请输入验证码", "max_length": "验证码过长", "min_length": "验证码过短" }, help_text="验证码") # allow_blank=False表示不能为空 username = serializers.CharField(required=True, allow_blank=False, label="用户名", validators=[UniqueValidator(queryset=UserProfile.objects.all(), message="用户已经存在")]) # 这里的style把密码设置为密文的, 就像input标签type属性设置为password一样 # write_only 将其设置True为确保在更新或创建实例时可以使用该字段,但在序列化表示时不包括该字段。 默认为 False password = serializers.CharField( style={'input_type': 'password'}, label="密码", write_only=True, ) def create(self, validated_data): # 获取到用户对象, 这个对象是继承了AbstractUser的用户对象 user = super(UserRegSerializer, self).create(validated_data=validated_data) # 所以这里有set_password方法 user.set_password(validated_data["password"]) # ModelSerializer是有save()方法的, save()方法会调用create函数, 我们在这里重置了create函数, 我们在这里加入里密码设置 user.save() return user def validate_code(self, code): """ 校验验证码 :param code: 验证码 :return: 验证码 """ # 在ModelSerializer前端传递过来的值都会放在initial_data里 # 校验验证码是否存在, 这里一定要排序, 这样才能获取最后的那条记录 这里的username就是mobile verify_records = VerifyCode.objects.filter(code=code, mobile=self.initial_data["username"]).order_by("-add_time") if verify_records: # 获取到最后一条记录 last_record = verify_records[0] # 校验验证码是否过期 # 获取5分钟前的时间 验证码有效期为5分钟 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("验证码错误") # 因为code只做验证, 所以这里不用吧code return回来 else: raise serializers.ValidationError("验证码错误") def validate(self, attrs): """ 校验所有的字段 :param attrs: attrs是所有字段组成的字典 :return: attrs """ # 因为mobile值就是username的值, 所以我们把username的值赋值给mobile attrs["mobile"] = attrs["username"] # 因为我们不需要code字段了, 所以这里可以直接删除 del attrs["code"] return attrs class Meta: model = UserProfile # username必填, 因为UserProfile继承了AbstractUser # 模型类写了必填, 你序列化的字段写了这个字段的话, 那么前端必须传这个字段的数据 fields = ( "username", "code", "mobile", "password" )
-
一般都不会从在serializer下从写create方法, 所以我们应该把从写的create注释掉, 用django的信号机制
-
signals
# post_save Django中的model对象保存后,自动触发 from django.db.models.signals import post_save from django.dispatch import receiver from django.contrib.auth import get_user_model # 获取用户模型类 UserProfile = get_user_model() # sender谁传递过来的 接受UserProfile传递过来的 @receiver(post_save, sender=UserProfile) # 在传递过来时它会不是是新建的, 因为update也会传递过来 # 这里的instance就是我们的UserProfile的对象 def create_auth_token(sender, instance=None, created=False, **kwargs): if created: # created为True就代表是新建的 password = instance.password instance.set_password(password) instance.save()
-
记住用了django信号机制, 记得在当前应用的apps下写ready方法把写信号机制的文件引入
from django.apps import AppConfig class UsersConfig(AppConfig): name = 'users' verbose_name = "用户信息" def ready(self): # 引入django信号机制所在模块 import users.signals
-
url
from rest_framework.routers import DefaultRouter from users.views import UserViewSet # 生成一个注册器实例对象 router = DefaultRouter() # 注册用户 router.register(r'users', UserViewSet, base_name="users") urlpatterns = [ # 自动生成url url(r"^", include(router.urls)), ]
-
效果图