Django之开发微信小程序后端-会话管理篇③


在这里插入图片描述

有状态服务

在这里插入图片描述

什么是状态

在这里插入图片描述

HTP协议中的状态

在这里插入图片描述

有状态服()

在这里插入图片描述

4-3 小程序的状态管理

在这里插入图片描述

小程序Stronge存储cookies

在这里插入图片描述

  • 在utils中设置cookies.js
    const key = 'cookie'
    
    function getSessionIDFromResponse(res){
      var cookie = res.header['Set-Cookie']
      console.log('get cookie from response: ', cookie)
      return cookie
    }
    
    function setCookieToStorage(cookie) {
      try {
        console.log(cookie)
        wx.setStorageSync(key, cookie)
      } catch (e) {
        console.log(e)
      }
    }
    
    function getCookieFromStorage() {
      var value = wx.getStorageSync(key)
      console.log(value)
      return value
    }
    
    
    module.exports = {
      setCookieToStorage: setCookieToStorage,
      getCookieFromStorage: getCookieFromStorage,
      getSessionIDFromResponse: getSessionIDFromResponse
    }
    
  • 测试在这里插入图片描述

Session中间件

在这里插入图片描述

4-4 实现登录功能

在这里插入图片描述

用户体系的建立

在这里插入图片描述

定义数据库模型


from django.db import models

# Create your models here.
class User(models.Model):
    # open_id
    open_id = models.CharField(max_length=64, unique=True)
    # 昵称
    nickname = models.CharField(max_length=256)
    # 关注的城市
    focus_cities = models.TextField(default='[]')
    # 关注的星座
    focus_constellations = models.TextField(default='[]')
    # 关注的股票
    focus_stocks = models.TextField(default='[]')

生成数据库模型

(venv) D:\Python_projects\backend-3-9>python manage.py makemigrations
Migrations for 'authorization':
  authorization\migrations\0001_initial.py
    - Create model User
 
(venv) D:\Python_projects\backend-3-9>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, authorization, contenttypes, sessions
Running migrations:
  No migrations to apply.

在这里插入图片描述
如果是测试号需要去申请去微信社区申请

前端从后端接口判断是否登录

// pages/homepage/homepage.js

const app = getApp()
const cookieUtil = require('../../utils/cookie.js')

Page({

  /**
   * 页面的初始数据
   */
  data: {},

  onReadCookies: function (){
    wx.request({
      url: app.globalData.serverUrl + app.globalData.apiVersion + '/auth/test',
      success(res) {
        var cookie = cookieUtil.getSessionIDFromResponse(res)
        console.log(cookie)
      }
    }
    )
  },

  // navigator跳转处理
  onNavigatorTap: function (event) {
    var that = this
    var cookie = cookieUtil.getCookieFromStorage()
    var header = {}
    header.Cookie = cookie
    wx.request({
      url: app.globalData.serverUrl + '/api/v1.0/auth/status',
      header: header,
      success: function (res) {
        var data = res.data.data
        console.log(data)
        if (data.is_authorized == 1) {
          that.setData({
            isLogin: true
          })
          app.setAuthStatus(true)
        } else {
          that.setData({
            isLogin: false
          })
          app.setAuthStatus(false)
          wx.showToast({
            title: '请先授权登录',
          })
        }

        if (data.is_authorized == 1){
          // 获取由 data-type 标签传递过来的参数
          console.log(event.currentTarget.dataset.type)
          var navigatorType = event.currentTarget.dataset.type
          if (navigatorType == 'focusCity') {
            navigatorType = 'city'
          } else if (navigatorType == 'focusStock') {
            navigatorType = 'stock'
          } else {
            navigatorType = 'constellation'
          }
          var url = '../picker/picker?type=' + navigatorType
          console.log('navigateTo url: ' + url)
          wx.navigateTo({
            url: '../picker/picker?type=' + navigatorType,
          })
        }
      }
    })
  },

登录时获取并存储cookie

  authorize: function () {
    console.log('authorize')
    var that = this
    // 登陆并获取cookie
    wx.login({
      success: function (res) {
        console.log(res)
        var code = res.code
        var appId = app.globalData.appId
        var nickname = app.globalData.userInfo.nickName
        // 请求后台
        wx.request({
          url: app.globalData.serverUrl + app.globalData.apiVersion + '/auth/authorize',
          method: 'POST',
          data: {
            code: code,
            appId: appId,
            nickname: nickname 
          },
          header: {
            'content-type': 'application/json' // 默认值
          },
          success(res) {
            wx.showToast({
              title: '授权成功',
            })
            // 保存cookie
            var cookie = cookieUtil.getSessionIDFromResponse(res)
            cookieUtil.setCookieToStorage(cookie)
            that.setData({
              isLogin: true,
              userInfo: app.globalData.userInfo,
              hasUserInfo: true
            })
            app.setAuthStatus(true)
          }
        })
      }
    })
  },

后端获取前端传递的个人信息openid

def __authorize_by_code(request):
    '''
    使用wx.login的到的临时code到微信提供的code2session接口授权

    post_data = {
        'encryptedData': 'xxxx',
        'appId': 'xxx',
        'sessionKey': 'xxx',
        'iv': 'xxx'
    }
    '''
    response = {}
    post_data = request.body.decode('utf-8')
    post_data = json.loads(post_data)
    app_id = post_data.get('appId').strip()
    nickname = post_data.get('nickname').strip()
    code = post_data.get('code').strip()
    print("code", code)
    print("app_id", app_id)
    if not (app_id and code):
        response['result_code'] = ReturnCode.BROKEN_AUTHORIZED_DATA
        response['message'] = 'authorized failed. need entire authorization data.'
        return JsonResponse(response, safe=False)
    try:
        data = c2s(app_id, code)
    except Exception as e:
        print(e)
        response['result_code'] = ReturnCode.FAILED
        response['message'] = 'authorized failed.'
        return JsonResponse(response, safe=False)
    open_id = data.get('openid')
    if not open_id:
        response['result_code'] = ReturnCode.FAILED
        response['message'] = 'authorization error.'
        return JsonResponse(response, safe=False)
    request.session['open_id'] = open_id
    request.session['is_authorized'] = True

    print("open_id", open_id)
    # User.objects.get(open_id=open_id) # 不要用get,用get查询如果结果数量 !=1 就会抛异常
    # 如果用户不存在,则新建用户
    if not User.objects.filter(open_id=open_id):
        new_user = User(open_id=open_id, nickname=nickname)
        new_user.save()

    message = 'user authorize successfully.'
    response = wrap_json_response(data={}, code=ReturnCode.SUCCESS, message=message)
    return JsonResponse(response, safe=False)

查看session_user

(venv) D:\Python_projects\backend-3-9>python manage.py dbshell
SQLite version 3.26.0 2018-12-01 12:34:55
Enter ".help" for usage hints.
sqlite> select * from authorization_user;
2|oXSML0ZH05BItFTFILfgCG6cTxik|咚咚呛!|[{"province": "\u5e7f\u4e1c\u7701", "area": "\u5357\u5c71\u533a", "city": "\u6df1\u5733\u5e02"}, {"province": "\u5e7f\u4e1c\u7701", "area": "\u76d0\u7530\u533a", "city": "\u6df1\u5733\u5e02"}]|["\u767d\u7f8a\u5ea7", "\u72ee\u5b50\u5ea7", "\u5904\u5973\u5ea7", "\u5c04\u624b\u5ea7"]|[{"name": "\u4e16\u7eaa\u661f\u6e90", "fullInfo": "\u6df1\u4ea4\u6240-\u4e16\u7eaa\u661f\u6e90(000005)", "market": "sz", "code": "000005"}, {"code": "000006", "name": "\u6df1\u632f\u4e1a\uff21", "fullInfo": "\u6df1\u4ea4\u6240-\u6df1\u632f\u4e1a\uff21(000006)", "market": "sz"}]
3|oRRtbv1RU2rC3zx2gTjoThOlLhas||[]|[]|[]
sqlite>

在这里插入图片描述

4-5 完善用户个人信息

在这里插入图片描述

查看个人信息

class UserView(View, CommonResponseMixin):
    # 关注的城市、股票和星座
    def get(self, request):
        if not already_authorized(request):
            response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
            return JsonResponse(response, safe=False)
        open_id = request.session.get('open_id')
        user = User.objects.get(open_id=open_id)
        data = {}
        data['open_id'] = user.open_id
        data['focus'] = {}
        print(user.focus_cities)
        data['focus']['city'] = json.loads(user.focus_cities)
        data['focus']['constellation'] = json.loads(user.focus_constellations)
        data['focus']['stock'] = json.loads(user.focus_stocks)
        print('data: ', data)
        response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, data=data)
        return JsonResponse(response, safe=False)

    def post(self, request):
        if not already_authorized(request):
            response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
            return JsonResponse(response, safe=False)
        open_id = request.session.get('open_id')
        user = User.objects.get(open_id=open_id)
        # got str object
        received_body = request.body.decode('utf-8')
        received_body = eval(received_body)

        cities = received_body.get('city')
        stocks = received_body.get('stock')
        constellations = received_body.get('constellation')
        if cities == None: cities = []
        if stocks == None: stocks = []
        if constellations == None: constellations = []

        user.focus_cities = json.dumps(cities)
        user.focus_constellations = json.dumps(constellations)
        user.focus_stocks = json.dumps(stocks)
        user.save()
        message = 'modify user info success.'
        response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, message=message)
        return JsonResponse(response, safe=False)

在这里插入图片描述

4-6 复杂多变的用户状态管理

在这里插入图片描述
在这里插入图片描述
pages/picker.js

const cookieUtil = require('../../utils/cookie.js')
const szStock = require('../../resources/data/stock/sz-100.js')
const shStock = require('../../resources/data/stock/sh-100.js')


var allStockData = []
Array.prototype.push.apply(allStockData, szStock.data)
Array.prototype.push.apply(allStockData, shStock.data)

const app = getApp()

Page({
  data: {
    isConstellPicker: false,
    isStockPicker: false,
    isCityPicker: false,
    personal: {
      constellation: [],
      city: [],
      stock: []
    },
    allPickerData: {
      allConstellation: ['白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座', '摩羯座', '水瓶座', '双鱼座'],
      allStock: []
    }
  },
  onLoad: function(options) {
    var that = this
    // 1. 判断类型
    console.log(options.type)
    this.setData({
      isConstellPicker: false,
      isStockPicker: false,
      isCityPicker: false,
    })
    if (options.type == 'city') {
      this.setData({
        isCityPicker: true,
      })
    } else if (options.type == 'constellation') {
      this.setData({
        isConstellPicker: true,
      })
    } else {
      this.setData({
        isStockPicker: true,
      })
    }
    var newPickerData = this.data.allPickerData
    newPickerData.allStock = allStockData
    this.setData({
      allPickerData: newPickerData
    })

    // 2. 加载数据
    var header = {}
    var cookie = cookieUtil.getCookieFromStorage()
    header.Cookie = cookie
    wx.request({
      url: app.globalData.serverUrl + '/api/v1.0/auth/user',
      method: 'GET',
      header: header,
      success(res) {
        console.log(res)
        that.setData({
          personal: res.data.data.focus
        })
      }
    })
  },

  bindConstellationPickerChange: function(e) {
    console.log('constellPicker发送选择改变,携带值为', e.detail.value)
    var newItem = this.data.allPickerData.allConstellation[e.detail.value]
    var newData = this.data.personal.constellation
    // 去重
    if (newData.indexOf(newItem) > -1)
      return
    newData.push(newItem)
    var newPersonalData = this.data.personal
    newPersonalData.constellation = newData
    this.setData({
      personal: newPersonalData
    })
  },

  bindStockPickerChange: function(e) {
    var newItem = this.data.allPickerData.allStock[e.detail.value]
    var newData = this.data.personal.stock
    // 去重
    for (var i = 0; i < newData.length; i++) {
      if (newData[i].name == newItem.name && newData[i].code == newItem.code && newData[i].market == newItem.market) {
        console.log('already exists.')
        return
      }
    }
    newData.push(newItem)
    var newPersonalData = this.data.personal
    newPersonalData.stock = newData
    this.setData({
      personal: newPersonalData
    })
  },

  bindRegionPickerChange: function(e) {
    console.log('cityPicker发送选择改变,携带值为', e.detail.value)
    var pickerValue = e.detail.value
    var newItem = {
      province: pickerValue[0],
      city: pickerValue[1],
      area: pickerValue[2],
    }
    var newData = this.data.personal.city
    // 去重
    for (var i = 0; i < newData.length; i++) {
      if (newData[i].province == newItem.province && newData[i].city == newItem.city && newData[i].area == newItem.area) {
        console.log('already exists.')
        return
      }
    }
    newData.push(newItem)
    var newPersonalData = this.data.personal
    newPersonalData.city = newData
    this.setData({
      personal: newPersonalData
    })
  },

  // 删除列表元素
  deleteItem: function(e) {
    var that = this
    var deleteType = e.currentTarget.dataset.type
    var index = e.currentTarget.dataset.index
    console.log('delete type: ' + deleteType)
    console.log('delete index: ' + index)
    var personalData = this.data.personal
    wx.showModal({
      content: "确认删除此项吗?",
      showCancel: true,
      success: function(res) {
        console.log(res)
        if (res.confirm) {
          if (deleteType == 'constellation') {
            personalData.constellation.splice(index, 1)
          } else if (deleteType == 'stock') {
            personalData.stock.splice(index, 1)
          } else {
            personalData.city.splice(index, 1)
          }
          that.setData({
            personal: personalData
          })
          that.onSave(false)
        }
      }
    })
  },

  // 保存后台
  onSave: function(isShowModal=true) {
    var that = this
    var header = {}
    var cookie = cookieUtil.getCookieFromStorage()
    header.Cookie = cookie
    wx.request({
        url: app.globalData.serverUrl + '/api/v1.0/auth/user',
        method: 'POST',
        data: {
          city: that.data.personal.city,
          stock: that.data.personal.stock,
          constellation: that.data.personal.constellation
        },
        header: header,
        success(res) {
          console.log(res)
          if (isShowModal){
            wx.showToast({
              title: '保存成功',
            })
        }
      }
    })
}
});
class UserView(View, CommonResponseMixin):
    # 关注的城市、股票和星座
    def get(self, request):
        if not already_authorized(request):
            response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
            return JsonResponse(response, safe=False)
        open_id = request.session.get('open_id')
        user = User.objects.get(open_id=open_id)
        data = {}
        data['open_id'] = user.open_id
        data['focus'] = {}
        print(user.focus_cities)
        data['focus']['city'] = json.loads(user.focus_cities)
        data['focus']['constellation'] = json.loads(user.focus_constellations)
        data['focus']['stock'] = json.loads(user.focus_stocks)
        print('data: ', data)
        response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, data=data)
        return JsonResponse(response, safe=False)

    def post(self, request):
        if not already_authorized(request):
            response = self.wrap_json_response(code=ReturnCode.UNAUTHORIZED)
            return JsonResponse(response, safe=False)
        open_id = request.session.get('open_id')
        user = User.objects.get(open_id=open_id)
        # got str object
        received_body = request.body.decode('utf-8')
        received_body = eval(received_body)

        cities = received_body.get('city')
        stocks = received_body.get('stock')
        constellations = received_body.get('constellation')
        if cities == None: cities = []
        if stocks == None: stocks = []
        if constellations == None: constellations = []

        user.focus_cities = json.dumps(cities)
        user.focus_constellations = json.dumps(constellations)
        user.focus_stocks = json.dumps(stocks)
        user.save()
        message = 'modify user info success.'
        response = CommonResponseMixin.wrap_json_response(code=ReturnCode.SUCCESS, message=message)
        return JsonResponse(response, safe=False)

4-7 有状态的首页(登录查询个人的添加记录)

首先判断是否登录,登录就从数据库中查询出数据,返回给前端展示,没有登陆提示未登录
在这里插入图片描述

# 星座运势
def constellation(request):
    data = []
    if already_authorized(request):
        user = get_user(request)
        print('星座:', user.focus_constellations)
        constellations = json.loads(user.focus_constellations)
    else:
        constellations = all_constellations
    for c in constellations:
        result = thirdparty.juhe.constellation(c)
        data.append(result)

    response = CommonResponseMixin.wrap_json_response(data=data, code=ReturnCode.SUCCESS)
    return JsonResponse(response, safe=False)


# 股票
def stock(request):
    data = []
    stocks = []
    if already_authorized(request):
        print("已登录")
        user = get_user(request)
        stocks = json.loads(user.focus_stocks)

    else:
        print("未登录")

        stocks = popular_stocks
    for stock in stocks:
        result = thirdparty.juhe.stock(stock['market'], stock['code'])
        data.append(result)
    response = CommonResponseMixin.wrap_json_response(data=data, code=ReturnCode.SUCCESS)
    return JsonResponse(response, safe=False)


# 笑话
def joke(request):
    global joke_cache
    if not joke_cache:
        joke_cache = json.load(open(os.path.join(settings.BASE_DIR, 'jokes.json'), 'r'))
    # 读缓存
    all_jokes = joke_cache
    limit = 10
    sample_jokes = random.sample(all_jokes, limit)
    response = CommonResponseMixin.wrap_json_response(data=sample_jokes, code=ReturnCode.SUCCESS)
    return JsonResponse(response, safe=False)

首页index.js

//index.js
//获取应用实例
const app = getApp()
const cookieUtil = require('../../utils/cookie.js')

Page({
  data: {
    isAuthorized: false,
    constellationData: null,
    stockData: null,
    weatherData: null
  },
  //事件处理函数
  bindViewTap: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },

  updateData: function() {
    wx.showLoading({
      title: '加载中',
    })
    var that = this
    var cookie = cookieUtil.getCookieFromStorage()
    var header = {}
    header.Cookie = cookie
    wx.request({
      url: app.globalData.serverUrl + app.globalData.apiVersion + '/service/weather',
      header: header,
      success: function(res){
        that.setData({
          weatherData: res.data.data
        })
        wx.hideLoading()
      }
    })
    wx.request({
      url: app.globalData.serverUrl + app.globalData.apiVersion + '/service/constellation',
      header: header,
      success: function (res) {
        that.setData({
          constellationData: res.data.data
        })
        wx.hideLoading()
      }
    })
    wx.request({
      url: app.globalData.serverUrl + app.globalData.apiVersion + '/service/stock',
      header: header,
      success: function (res) {
        that.setData({
          stockData: res.data.data
        })
        wx.hideLoading()
      }
    })
  },

  onPullDownRefresh: function() {
    var that = this
    var cookie = cookieUtil.getCookieFromStorage()
    var header = {}
    header.Cookie = cookie
    wx.request({
      url: app.globalData.serverUrl + app.globalData.apiVersion + '/auth/status',
      header: header,
      success: function(res){
        var data = res.data.data
        if (data.is_authorized == 1){
          that.setData({
            isAuthorized: true
          })
          that.updateData()
        }else{
          that.setData({
            isAuthorized: false
          })
          wx.showToast({
            title: '请先授权登录',
          })
        }
      }
    })
  },

  onLoad: function() {
    if (app.globalData.userInfo) {
      this.setData({
        userInfo: app.globalData.userInfo,
        hasUserInfo: true
      })
    } else if (this.data.canIUse) {
      // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
      // 所以此处加入 callback 以防止这种情况
      app.userInfoReadyCallback = res => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    } else {
      // 在没有 open-type=getUserInfo 版本的兼容处理
      wx.getUserInfo({
        success: res => {
          app.globalData.userInfo = res.userInfo
          this.setData({
            userInfo: res.userInfo,
            hasUserInfo: true
          })
        }
      })
    }
  },
  getUserInfo: function(e) {
    console.log(e)
    app.globalData.userInfo = e.detail.userInfo
    this.setData({
      userInfo: e.detail.userInfo,
      hasUserInfo: true
    })
  }
})

猜你喜欢

转载自blog.csdn.net/weixin_43746433/article/details/106446211