注册有两种逻辑
- 注册以后自己去登入
- 注册以后我们帮他直接登入
这里讲解的是第二种, 第一种直接把我第二种添加的代码删除掉就行
-
前端代码-vue—注册是登入需要name和token–不想注册时直接登入把then下的三行代码删除掉, 留着跳转哪行代码就行
<input class="btn btn-green" id="jsMobileRegBtn" @click="isRegister" type="button" value="注册并登录"> // isRegister实在methods里的 isRegister(){ var that = this; register({ password:that.password, username:that.mobile , code:that.code, }).then((response)=> { // 我们这种模式是注册以后直接帮他登入了, 如果你想注册以后让他自己登入, 就把下面3行代码注释掉, 留着跳转页面哪行代码就行 cookie.setCookie('name',response.data.username,7); cookie.setCookie('token',response.data.token,7) //存储在store // 更新store数据 that.$store.dispatch('setInfo'); //跳转到首页页面 this.$router.push({ name: 'index'}) }) .catch(function (error) { that.error.mobile = error.username?error.username[0]:''; that.error.password = error.password?error.password[0]:''; that.error.username = error.mobile?error.mobile[0]:''; that.error.code = error.code?error.code[0]:''; }); } -
views–不想注册时就登入就把我重写的方法全部删除掉就行了–留着queryset和serializer_class就行
from django.contrib.auth import get_user_model from rest_framework.mixins import CreateModelMixin from rest_framework import viewsets # 返回的响应体 from rest_framework.response import Response # 状态码 from rest_framework import status # jwt_payload_handler 是生成payload的 # jwt_encode_handler 是生成token的 from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler 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() # 因为我们是用户注册以后就直接帮用户登入, 所以我们要返回个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 perform_create(self, serializer): # 返回的serializer关联的model对象 return serializer.save() # 退出我们不用写接口, 因为JWT把token是放在客户端的, 前端只要清楚cookie就ok了 -
url
from django.conf.urls import url, include 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)), ] -
serializer–这里是重写ModelSerializer里的create方法来加密用户密码的, 但是我这里把它注释了, 用的django信号机制解决的, 这样分离性更强
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" ) -
signals–django型号机制
# 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
浙公网安备 33010602011771号