前言:
眼前各位老铁们对“as登录注册”大概比较讲究,兄弟们都想要分析一些“as登录注册”的相关知识。那么小编在网络上汇集了一些对于“as登录注册””的相关文章,希望你们能喜欢,看官们一起来学习一下吧!前言
本章内容主要完成以下几个内容:
1、django切换sqllite至mysql
2、 用户注册功能
3、JWT用户认证功能
4、 获取用户信息
因为个人并不喜欢使用django 的 “视图集” ,所以后续的内容会使用“类视图”来实现API
1、django切换sqllite至mysql
下载依赖
pip install -i pymysql
将settings中DATABASES的配置修改为mysql
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'testplatform', 'USER': 'root', 'PASSWORD': 'root', 'HOST': 'localhost', 'PORT': '3306', }}12345678910
需要在 TestPlatform/init.py中添加
import pymysqlpymysql.version_info = (1, 4, 0, "final", 0)pymysql.install_as_MySQLdb()1232、用户注册功能
用户是一个独立的模块,所以这里我们继续采用之前的“老四样”:
1、新建APP
python manage.py startapp users
2、将APP注册在settings.py文件中
INSTALLED_APPS=[ + users.apps.UsersConfig]
3、实现业务逻辑
4、将url注册在urls.py文件中
2.1定义用户数据模型
第一步,第二步没有什么异议,只是我们需要在settings.py中增加一些内容
# 使用 新定义的user 不用django 的UserAUTH_USER_MODEL = 'users.User'12
然后在models.py中定义User类
from django.contrib.auth.models import AbstractUserfrom django.db import models# Create your models here.class User(AbstractUser): ''' 用户信息表 ''' name = models.CharField(max_length=32, null=False, blank=False, verbose_name="姓名") mobile = models.CharField(max_length=11, unique=True, null=False, blank=False, verbose_name="电话") email = models.EmailField(max_length=128, unique=True,null=False, blank=False, verbose_name="邮箱") # username 不做唯一处理 username = models.CharField(max_length=30, unique=False) USERNAME_FIELD = 'mobile' class Meta: # 联合约束 mobile ,email不能重复 unique_together = ["mobile", "email"] verbose_name = '用户' verbose_name_plural = '用户' def __str__(self): return self.name1234567891011121314151617181920212223242526
AbstractUser类是django自带的用户类,我们继承这个类,添加一些我们需要的字段。AbstractUser默认username是唯一的,不符合我们的设计要求,所以 我将 USERNAME_FIELD 设置为’mobile’
执行命令行,自动生成模型相关的数据库表结构:
python manage.py makemigrations
python manage.py migrate
2.2 serializer 序列化
序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据
class UserRegSerializer(serializers.ModelSerializer): name = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False) mobile = serializers.CharField(label="手机号", help_text="手机号", required=True, allow_blank=False, validators=[UniqueValidator(queryset=User.objects.all(), message="手机号已经存在")]) email = serializers.EmailField(label="邮箱号", help_text="邮箱号", required=True, allow_blank=False, validators=[UniqueValidator(queryset=User.objects.all(), message="邮箱号已经存在")]) password = serializers.CharField( style={'input_type': 'password'}, help_text="密码", label="密码", write_only=True, ) class Meta: model = User fields = ("name", "mobile", "email", 'password')123456789101112132.3 定义统一的返回格式
web开发中,通常我们会将系统返回的Reponse统一格式,方便前端获取数据。
我们再utilsapp/common中定义统一的返回数据
# 自定义状态码class HttpCode(object): # 正常登陆 ok = 200 # 参数错误 paramserror = 400 # 权限错误 unauth = 401 # 方法错误 methoderror = 405 # 服务器内部错误 servererror = 500# 定义统一的 json 字符串返回格式def result(code=HttpCode.ok, message="", data=None, kwargs=None): json_dict = {"code": code, "message": message, "data": data} # isinstance(object对象, 类型):判断是否数据xx类型 if kwargs and isinstance(kwargs, dict) and kwargs.keys(): json_dict.update(kwargs) return Response(json_dict)def ok(): return result(message="success")def ok_data(data=None): return result(data=data,message="success")# 参数错误def params_error(message="params error", data=None): return result(code=HttpCode.paramserror, message=message, data=data)# 权限错误def unauth(message="", data=None): return result(code=HttpCode.unauth, message=message, data=data)# 方法错误def method_error(message="methods error", data=None): return result(code=HttpCode.methoderror, message=message, data=data)# 服务器内部错误def server_error(message="server error", data=None): return result(code=HttpCode.servererror, message=message, data=data)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051522.4 用户注册业务逻辑
字段的校验逻辑 在UserRegSerializ类中已经声明了,我们这里直接将接口的数据request.data 获取,进行校验,符合规则就保存
class UserRegisterView(CreateAPIView): serializer_class = UserRegSerializer permission_classes = [AllowAny] def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): serializer.save() return ok() else: return params_error(message=serializer.errors)1234567891011
因为这里是直接保存,所以我们通过接口传过来的 password 字段也是明文保存到数据库中,这显然是不合理的。
在django 中我们使用 signals(信号)------允许解耦的应用在框架的其它地方发生操作时会被通知到,也就是说在特定事件发生时,可以发送一个信号去通知所有注册了这个信号的回调,在回调里进行想要的操作处理。
这里我们使用 post_save 方法,在调用save方法之后,对models进行操作,也就是对密码加密
User = get_user_model()@receiver(post_save, sender=User)def create_user(sender, instance=None, created=False, **kwargs): if created: password = instance.password instance.username = instance.email instance.set_password(password) instance.save()12345678
这里还有一步操作
instance.username = instance.email
我们希望将email 作为唯一的username进行存储,使用mobile 也可以
2.5 添加urls,并调试
我们按照之前文档的步骤,添加urls
urlpatterns = [ path('register', views.UserRegisterView.as_view(), name='register'), ]123
然后调试
数据库中的数据
3、JWT用户认证功能
json web token 简称JWT ,建议不知道这个概念的小伙伴 搜索一下相关资料,这里不做过多讲解。
下载依赖
pip install -i djangorestframework-jwt
3.1 定义token返回
因为我们集成了django 自带的 “ModelBackend” 类,我们如果不定义格式的话,会直接返回 token,为了保持统一格式,我们这里需要定义一个新的 ‘JWT_RESPONSE_PAYLOAD_HANDLER’,来保证格式的统一。
在 users/utils.py 中定义一个方法
def jwt_response_payload_handler(token, user=None, request=None): """ 自定义jwt认证成功返回数据 """ return {"code": 200, "message": "登录成功", "data": {"token": token}}123453.2 用户认证接口
我们再users/views.py中定义我们的登录接口,我们先通过 User.objects.get()方法来查询是否存在用户,其中 Q 的使用是 django.db.models 中的一个方法,等同于我们的mysql 语句
where email =xxx or mobile =xxx
然后通过check_password ,校验密码是否正确。
class CustomBackend(ModelBackend): """ 自定义用户验证 """ def authenticate(self, username=None, password=None, **kwargs): try: user = User.objects.get(Q(email=kwargs['mobile']) | Q(mobile=username)) if user.check_password(password): return user except Exception as e: return None1234567891011123.3 注册相关信息
在settings.py文件中注册我们刚才完成的信息
REST_FRAMEWORK = { # rest framework的认证机制 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ),}import datetimeJWT_AUTH = { 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), 'JWT_AUTH_HEADER_PREFIX': 'JWT', # 自定义JWT返回数据 'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',}AUTHENTICATION_BACKENDS = ( 'users.views.CustomBackend', # 用户自定义认证 'django.contrib.auth.backends.ModelBackend',)12345678910111213141516171819203.4 调试
将接口信息添加至urls.py ,启动服务器就可以进行调试了
4、获取用户信息
我们在view.py中新增了一个 UserInfoView 类,并让这个类继承了 RetrieveAPIView 这个视图类,表示 获取 单个数据
IsAuthenticated:必须登录用户;
permission_classes = (IsAuthenticated,)用来做用户认证的
authentication_classes = (JSONWebTokenAuthentication,SessionAuthentication)
class UserInfoView(RetrieveAPIView): serializer_class = UserDetailSerializer authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication) def get(self, request, *args): user_id = request.GET.get('id') if request.user.id != int(user_id): return unauth(message="无法查询他人信息") else: user = User.objects.filter(id=user_id) user_info_str = serializers.serialize('json', user, fields=("name", "email", "mobile")) user_info = json.loads(user_info_str) return ok_data(data=user_info[0].get("fields"))1234567891011121314
新增 UserInfosView 类 ,并让这个类继承了 ListAPIView 这个视图类,表示 获取多个数据。我们知道在获取多数据的时候,如果不做分页,会对 数据库造成很大的压力,所以我们这里同时实现了一个分页的功能
class UsersPagination(PageNumberPagination): ''' 商品列表自定义分页 ''' # 默认每页显示的个数 page_size = 10 # 可以动态改变每页显示的个数 page_size_query_param = 'page_size' # 页码参数 page_query_param = 'page' # 最多能显示多少页 max_page_size = 100class UserInfosView(ListAPIView): serializer_class = UserDetailSerializer queryset = User.objects.all() # 分页 pagination_class = UsersPagination authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication) def get(self, request, *args, **kwargs): user_infos_str = serializers.serialize('json', self.queryset.all().order_by('-id'), fields=("name", "email", "mobile")) user_infos = json.loads(user_infos_str) # 实例化分页对象,获取数据库中的分页数据 paginator = UsersPagination() page_user_list = paginator.paginate_queryset(user_infos, self.request, view=self) json_list = [] for user in page_user_list: user_info = user.get("fields") json_list.append(user_info) return ok_data(json_list)12345678910111213141516171819202122232425262728293031323334
接口调试:
单一数据接口
多数据接口:
5、总结
可能有人会觉得上面的代码很不“django ”,明明已经有很多封装好的东西没有拿来直接使用,而重新完成了一些逻辑 。
因为个人觉得直接使用django的 “视图集” 封装得太多,不看源码的话不知道这些类,方法 到底是做什么的,而且在这个项目中,我需要自己定制化一些东西,所以我选择 APIView 进行开发。
如果你有想实现的功能欢迎提交
本项目的代码已上传git
(本章内容分支 git checkout user)
标签: #as登录注册 #django获取登录的用户名 #django登录界面代码