python卷java实现api接口提供(三)

前言

首先跟追我博文的博友告歉,这篇之后可能要得1周后才能继续。爱人到了需要取钉的时间要入院陪护,所以我下周是没有办法写了,望各位博友见谅。

娃少喝的奶,她记你一世。抗疫有你,铭记一生。


这次跟大家分享python的数据库操作、redis集成,下面就通过一个登录接口体现。

一、redis集成依赖

需要安装依赖包:django-redis
安装方式这里也不重复说了,看前面的博文。

二、登录

1.用户登录设计

现在一般用户表设计:
1、密码密文存储
2、登录后生成token
3、登录多用手机号 + 密码,或账号 + 手机验证码
这里前面在做用户新增的时候,做了自定义的设置密码字段值,这里调整下逻辑,与这里手机号登录配合
models.py修改

# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
#   * Rearrange models' order
#   * Make sure each model has one field with primary_key=True
#   * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
#   * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from django import forms
from django.contrib.auth.hashers import make_password
from django.db import models


class UserInfo(models.Model):
    id = models.AutoField(verbose_name='主键', primary_key=True, unique=True)
    name = models.CharField(verbose_name='姓名', max_length=200, blank=True, null=True)
    mobile = models.CharField(verbose_name='手机号', max_length=20, blank=True, null=True)
    # 性别
    sexChoices = (
        (1, '男'), (0, '女')
    )
    sex = models.IntegerField(verbose_name='性别', blank=True, choices=sexChoices, null=True)
    nickname = models.CharField(verbose_name='昵称', max_length=30, null=True)
    password = models.CharField(verbose_name='密码', max_length=128, default='')
    salt = models.CharField(verbose_name='盐值', max_length=10, default='123456')
    memo = models.CharField(verbose_name='备注', max_length=500, blank=True, null=True)
    create_by = models.IntegerField(verbose_name='创建人ID', blank=True, null=True)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True, blank=True, null=True)
    delChoices = ((0, '否'), (1, '是'))
    is_deleted = models.IntegerField(verbose_name='是否删除', default=0, choices=delChoices, blank=True, null=True)

    # 关联查询时返回内容
    def natural_key(self):
        return {
    
    
            "id": str(self.id),
            "name": str(self.name),
            'nickname': str(self.nickname),
            "mobile": str(self.mobile),
            "sex": str(self.sex)
        }
        # 将属性和属性值转换成dict 列表生成式

    # 自定义转字典
    def toDict(self):
        return dict([(attr, getattr(self, attr)) for attr in
                     [f.name for f in self._meta.fields]])

    class Meta:
        managed = False
        db_table = 'user_info'
        ordering = ['-create_time']
        verbose_name = '用户信息'
        verbose_name_plural = '用户信息'

    # 修改&添加提交时被执行,对密码进行加密
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        # if len(str(self.salt)) == 0:
        #    self.salt = self.password
        # 密码加密,使用盐值加密
        # self.password = make_password(self.password, self.salt)
        self.password = make_password(self.password, self.mobile)
        super().save(force_insert=False, force_update=False, using=None, update_fields=None)

变更点:
1、表数据自定义转字典的方法,见toDict(self)方法
2、数据入库的password字段值逻辑调整,见def save()方法

2.登录接口

import json

import django_redis
from django.contrib.auth.hashers import check_password
from django.core import serializers, signing
from django.core.paginator import Paginator
from django.core.serializers import serialize
from django.http import JsonResponse

from django.views.decorators.csrf import csrf_exempt

from user.models import UserInfo


# Create your views here.

# @csrf_exempt表示视图可以进行跨域请求
@csrf_exempt
def userLogin(request):
    # 统一响应对象
    response = {
    
    
        'code': 200,
        'success': True,
        'msg': '成功'
    }
    try:
        body = json.loads(request.body.decode("utf-8"))
        # 请求参数
        param = {
    
    }
        param['mobile'] = body['mobile']
        param['password'] = body['password']
        # python判断空特别要注意‘’不代表就是None
        if param['password'] is None or not param['password'] or param['mobile'] is None or not param['mobile']:
            response['msg'] = '手机号或密码为空'
            response['code'] = 20001
            response['success'] = '失败'
            return JsonResponse(response)
        else:
            list = UserInfo.objects.filter(mobile=param['mobile']).all()
            if list.count == 0:
                response['msg'] = '用户信息不存在'
                response['code'] = 20002
                response['success'] = '失败'
                return JsonResponse(response)
            else:
                # 就直接取第一条了
                user = list.first()
                dbPassword = user.password
                # django的自带密码反向校验
                res = check_password(param['password'], dbPassword)
                if res:
                    token = signing.dumps(param)
                    # redis连接获取
                    cache = django_redis.get_redis_connection()
                    # 拼接字符串,大量推荐用这个,少量可以用+
                    key = ":".join(['zwDjangoProject', param['mobile']])
                    print(key)
                    # 缓存key
                    cache.set(key, token, 30)
                    # 直接把token放入data返回
                    # response['data'] = token
                    # 对象多加一个token属性,有一说一:这里跟java不一样,如果对象没有这个属性java没法set,这里这点还不错
                    user.token = token
                    # 对象转字典自带__dict__方法
                    # userDict = user.__dict__
                    # print(userDict)
                    # 字典toString
                    # userDict.__str__()
                    # 这里这样处理的对象,实际上data就是一整个字符串,还是不是有嵌套的json字符串
                    # response['data'] = userDict.__str__()

                    # 下面这里把字典转json字符串失败,不能直接像java那样转json字符串
                    # print(userDict)
                    # userJsonStr = json.dumps(user.__dict__)
                    # print(userJsonStr)
                    # response['data'] = userJsonStr
                    # response['data'] = user

                    # 这种方式也是失败的,以为是date类型字段导致,还做了删除元素
                    # userJsonStr = serialize('json', user, use_natural_foreign_keys=False)
                    # print(userJsonStr)
                    # response['data'] = userJsonStr
                    # userDict.pop('_state')
                    # userDict.pop('create_time')
                    # userJsonStr = serialize('json', user)
                    # print(userJsonStr)
                    # response['data'] = userJsonStr

                    # 下面是我走通的:不直接使用__dict__,在models.py自定义转字典的方法。应该还有其他方法,后面再补充
                    userDict = user.toDict()
                    userDict['token'] = token
                    response['data'] = userDict
                    return JsonResponse(response)
                else:
                    response['msg'] = '密码错误'
                    response['code'] = 20003
                    response['success'] = '失败'
                    return JsonResponse(response)

    except:
        response['data'] = ''
        response['code'] = 500
        response['msg'] = '失败'
    # 响应结果对象
    return JsonResponse(response)


@csrf_exempt
def userList(request):
    print(request.method)
    # 统一响应对象
    response = {
    
    
        'code': 200,
        'success': True,
        'msg': '成功'
    }
    try:
        body = json.loads(request.body.decode("utf-8"))
        # 请求参数
        param = {
    
    }
        param['page'] = body['page']
        param['size'] = body['size']
        param['name'] = body['name']
        param['mobile'] = body['mobile']

        # 数据
        list = UserInfo.objects.all()
        # 查询数据:模糊查询
        if param['name'] is not None:
            list = list.filter(name__contains=param['name'])
        if param['mobile'] is not None:
            list = list.filter(mobile__contains=param['mobile'])
        # 分页插件
        paginator = Paginator(list, param['size'])
        # 获取总条数
        response['total'] = paginator.count
        # 获取当前页数据集合
        records = paginator.page(param['page'])
        # 将数据序列化为json对象,并且关联查询外键的数据
        response['data'] = json.loads(serializers.serialize('json', records, use_natural_foreign_keys=True))
    except:
        response['data'] = ''
        response['code'] = 500
        response['msg'] = '失败'
    # 响应结果对象
    return JsonResponse(response)

接口说明

  • 登录接口见userLogin()方法,这里是手机号 + 密码方式登录。
  • 登录逻辑大致就是根据手机号查询用户,匹配加密的密码是否相等
  • 数据库查询操作使用的是django自带的orm框架,框架有部分约定缩成的编码方式,比如字段过滤那块
  • redis这里也是django的支持,使用思路也特简单,就是获取redis连接,设置缓存信息
  • token生成也是使用的django自带的,这个有对应的反向校验方法(注意为防止被反算,可以跟对象补充设置一个salt属性,再进行dumps)
  • 对象序列化,转json,代码里面试验了几种方式,最终还是自定义的转字典方法后再转json靠谱
  • 其他的也不多说了,代码上码有些注释

3.查看登录效果

在这里插入图片描述


总结

  • 1、对象增加不存在的属性,设置值方便,都不用像java那样设置属性,注解表示表不存在,这里直接就可以:对象.xxx = aaaa
  • 2、对象转json有点费劲(不知道有没有类似fastjson、hutool的相关工具包)
    下一阶段
    1、先试试django的多表表连接查询
    2、restful风格接口
    3、找找是否有相关类似hutool的工具包
    希望能帮到大家,技术人,加油。

猜你喜欢

转载自blog.csdn.net/zwrlj527/article/details/122304043