动态指定序列化类–动态指定权限–具体操作在views里
-
signals–django的信号机制–我们这里用django的信号机制,而不是从写ModelSerializer里的create方法,是因为这样分离性更强
# 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()
-
serializer
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 UserDetailSerializer(serializers.ModelSerializer): class Meta: model = UserProfile fields = ( "name", "birthday", "gender", "email", "mobile" ) 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="用户名", help_text="用户名", 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, help_text="密码", ) # def create(self, validated_data): # ModelSerializer序列化好了的数据都放在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里---原始数据 # ModelSerializer序列化好了的数据都放在validated_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 """ print("attrs", attrs, type(attrs), attrs["username"]) # 因为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" )
-
views
from django.contrib.auth import get_user_model from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework import viewsets # 返回的响应体 from rest_framework.response import Response # 状态码 from rest_framework import status # IsAuthenticated判断用户是否登入 from rest_framework.permissions import IsAuthenticated # jwt_payload_handler 是生成payload的 from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework.authentication import SessionAuthentication from .serializers import UserRegSerializer, UserDetailSerializer # 获取用户模型类 UserProfile = get_user_model() class UserViewSet(CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, viewsets.GenericViewSet): """ create: 用户注册 retrieve: 获取用户信息 update: 修改用户信息 """ # 会调用ModelSerializer的create或者update方法, # 如果继承的是Serializer,就需要自己重载Serializer中的create或者update方法,或者修改mixins的create等方法的逻辑进行保存 # serializer_class = UserRegSerializer queryset = UserProfile.objects.all() # json token的验证 局部大于全局, 就算你在全局设置过, 但是你只要在这里加上authentication_classes 就会替换全局设置 authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication) # 动态指定序列化类 def get_serializer_class(self): # action是访问的方法 if self.action == "create": return UserRegSerializer elif self.action == "retrieve": return UserDetailSerializer elif self.action == "update": return UserDetailSerializer return UserDetailSerializer # IsAuthenticated==要获取或修改当前用户信息, 必须登入 # permission_classes = (IsAuthenticated, ) 但是这里注册的话就不行了 # 所以重写permissions方法 # 来动态指定permission def get_permissions(self): # action是访问的方法 if self.action == "create": return [] elif self.action == "retrieve": return [IsAuthenticated()] elif self.action == "update": return [IsAuthenticated()] # 其他情况 return [] # 因为我们是用户注册以后就直接帮用户登入, 所以我们要返回个token, 所以我们要重写create def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 我们这里要重载perform_create方法, 因为perform_create没有返回值 user = self.perform_create(serializer) # 因为Response返回的是serializer.data, 所以我们应该把token放进去 re_dict = serializer.data # 生成payload payload = jwt_payload_handler(user) # 生成user--JWT的token 并把token添加到serializer.data里, 这样我们Response返回就应该返回re_dict了 # jwt_encode_handler(payload)生成token re_dict["token"] = jwt_encode_handler(payload) # 因为前端还需要个name re_dict["name"] = user.name if user.name else user.username headers = self.get_success_headers(serializer.data) return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers) def get_object(self): # 返回一个具体的对象 # 这个方法, 只会在RetrieveModelMixin, UpdateModelMixin会执行 # 返回当前用户信息 return self.request.user def perform_create(self, serializer): # 返回的serializer关联的model对象 return serializer.save()
-
url
from rest_framework.routers import DefaultRouter # 生成一个注册器实例对象 router = DefaultRouter() # 注册用户 router.register(r'users', UserViewSet, base_name="users") urlpatterns = [ # 自动生成url url(r"^", include(router.urls)), ]