昨日内容回顾

  1. 第一部分:考试题(Python基础)
  2. 第二部分:路飞相关
  3. 1. 是否遇到bug?难解决的技术点?印象深刻的事?
  4. - orm操作费劲
  5. - 最开始学习路由系统时候,匹配规则;
  6. 答案一:
  7. 有,但主要不是在技术上而是在业务上;在支付时:贝里、支付宝、满减、立减、折扣;
  8. 答案二:
  9. 编写API时,如果继承ModelViewSet相关的类之后,必须在静态字段中写:queryset
  10. class AuthView(ModelViewSet):
  11. queryset = models.xxx.all()
  12. 否则,在渲染器渲染好看的页面时,会报错。
  13. 解决方案:
  14. a. 不继承,继承APIView
  15. b. 定义渲染器
  16. class AuthView(GenaricViewSet):
  17. render_classes = [JSONrender,]
  18. queryset = models.xxx.all()
  19. 答案三:
  20. 在刚学习时候,xxxxxxx
  21. 大忌:非常简单的功能
  22. 2. 路飞学城项目架构是怎么样?
  23. - 管理后台
  24. - 导师后台
  25. - 主站
  26. - 前端:1
  27. - 后端:3人(1+0.5+1+0.5+0.5
  28. - UI1
  29. 3. 路飞学城中你负责写过什么?
  30. API:
  31. - 第一类:基本增删改查
  32. - 课程列表
  33. - 学位课
  34. - 专题课
  35. - 课程详细
  36. - 课程大纲
  37. - 价格策略
  38. - 推荐课程
  39. - 课程章节
  40. - 用户评价
  41. - 常见问题
  42. - 文章列表
  43. - 文章详细
  44. - 评论
  45. - 点赞
  46. - 收藏
  47. - 学习中心
  48. - 我的账户
  49. - 我的订单
  50. - 作业
  51. - 回答
  52. - 提问
  53. ...
  54. - 第二类:支付流程
  55. - 购物车
  56. - 加入购物车
  57. - 查看
  58. - 修改价格策略
  59. - 删除购物车中的课程
  60. 4. 路飞学城购物车的结构?

一、微信消息推送

面对大量的垃圾信息拟门会报告垃圾短信,导致了大部分消息推送方式的失效或者效果打折,今天谈的是效果非常好的微信通知服务

因为这里推送的都是有效信息,屏蔽的人非常少,微信不允许你把它当做推广工具,所以都有调用次数等规则限制,但我们可以好好利用以保持应用的用户粘性。

公众号

公众号分别3种:订阅号,服务号,企业号。

其中订阅号,分为未认证和已认证。已认证需要公司营业执照相关信息,服务号和企业号,也需要公司相关信息。

基于沙箱环境做消息推送

由于用户体验和安全性方面的考虑,微信公众号的注册有一定门槛,某些高级接口的权限需要微信认证后才可以获取。

所以,为了帮助开发者快速了解和上手微信公众号开发,熟悉各个接口的调用,我们推出了微信公众帐号测试号,通过手机微信扫描二维码即可获得测试号。

进入微信公众帐号测试号申请系统

Day103 微信消息推送,结算中心业务流程 - 图1

单击登录,扫描一下二维码

打开手机微信,确认登录

Day103 微信消息推送,结算中心业务流程 - 图2

进入之后,就会有一个测试账号

接下来的代码,需要使用appID和appsecret

Day103 微信消息推送,结算中心业务流程 - 图3

网页的表单,一律不需要填写!!!

找到下面的测试好二维码,将图片下载下来

直接右键—>另存为即可

Day103 微信消息推送,结算中心业务流程 - 图4

项目测试

新建一个项目wxbox,注意:django版本为1.11

修改urls.py

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from app01 import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. url(r'^index/', views.index),
  7. ]

将templates目录剪切到app01目录下,在app01目录下,创建static。为什么这么做呢?

因为这样的话,每一个应用都有独立的templates和static。

那么django能找到它吗?

默认是从项目根目录查找,如果找不到,会从应用名目录中取找。找不到,就报错!

将下载的图片放到static中,新建index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>欢迎使用:路飞学城</h1>
  9. <h3>扫描关注路飞学诚(用于消息提示,请必须关注)</h3>
  10. <img style="width: 200px;" src="/static/0.jpg" alt="">
  11. </body>
  12. </html>

修改views.py

  1. from django.shortcuts import render,HttpResponse
  2. # Create your views here.
  3. def index(request):
  4. """
  5. 首页
  6. :param request:
  7. :return:
  8. """
  9. return render(request,"index.html")

启动django项目,访问首页

Day103 微信消息推送,结算中心业务流程 - 图5

获取用户的微信id

使用另外一个微信号,扫描一下,点击关注

Day103 微信消息推送,结算中心业务流程 - 图6

这里会出现一个微信号

Day103 微信消息推送,结算中心业务流程 - 图7

注意:这里的微信号,并不是真正的微信号,它是一段随机码。它只是和这个公众号做了一下绑定,为了唯一标识这个用户!

假设这个用户,由关注了别的公众号。那么会出现一个新的随机码!

也就是说:不同公众号,同一个人,是不一样的!

脚本测试

使用前,安装模块

  1. pip3 install requests

获取token

因为要向用户发送消息,所以需要使用token认证,才能发送!

在项目根目录创建 test.py

注意:修改里面的appid和secret,改为自己的

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import json
  4. import requests
  5. # 1. 伪造浏览器向 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential... 发送GET请求,并获取token
  6. r1 = requests.get(
  7. url="https://api.weixin.qq.com/cgi-bin/token",
  8. params={
  9. "grant_type": "client_credential",
  10. "appid": 'wx038ba9d6c87fxxxx',
  11. "secret": 'fd1ebdff49010aa67a1457bbe250xxxx',
  12. }
  13. )
  14. print(r1.text) # 获取文本
  15. print('*'*30)
  16. print(r1.json()) # 反序列化
  17. print('*'*30)
  18. access_token = r1.json().get('access_token') # 获取token
  19. print(access_token)

执行输出:

  1. {"access_token":"12_23d1iIREKvhS0N6EislyKdaV9MhcaXgBAgTnH_5ivrobK4Ek6uoD9_35nvlL8SO76dGQ-T6wnzmVaXi3wHhCigaw85JqMV47DM0rq664ZEYdfOWypvyplByJ6yts-F3RYthMkWtfG-bGyyzDYZVfADAGHD","expires_in":7200}
  2. ******************************
  3. {'expires_in': 7200, 'access_token': '12_23d1iIREKvhS0N6EislyKdaV9MhcaXgBAgTnH_5ivrobK4Ek6uoD9_35nvlL8SO76dGQ-T6wnzmVaXi3wHhCigaw85JqMV47DM0rq664ZEYdfOWypvyplByJ6yts-F3RYthMkWtfG-bGyyzDYZVfADAGHD'}
  4. ******************************
  5. 12_23d1iIREKvhS0N6EislyKdaV9MhcaXgBAgTnH_5ivrobK4Ek6uoD9_35nvlL8SO76dGQ-T6wnzmVaXi3wHhCigaw85JqMV47DM0rq664ZEYdfOWypvyplByJ6yts-F3RYthMkWtfG-bGyyzDYZVfADAGHD

给指定用户发送消息

复制这里面的微信号,它可以定位到这个用户

Day103 微信消息推送,结算中心业务流程 - 图8

修改test.py,指定微信号

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import json
  4. import requests
  5. # 1. 伪造浏览器向 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential... 发送GET请求,并获取token
  6. r1 = requests.get(
  7. url="https://api.weixin.qq.com/cgi-bin/token",
  8. params={
  9. "grant_type": "client_credential",
  10. "appid": 'wx038ba9d6c87fxxxx',
  11. "secret": 'fd1ebdff49010aa67a1457bbe250dxxx',
  12. }
  13. )
  14. # print(r1.text) # 获取文本
  15. # print('*'*30)
  16. # print(r1.json()) # 反序列化
  17. # print('*'*30)
  18. access_token = r1.json().get('access_token') # 获取token
  19. # print(access_token)
  20. # 2. 给指定用户发送普通消息消息:access_token/
  21. wx_id = 'oe0j758m-Zp4QBOvgzF8vGBCOxxx' # 微信号
  22. body = {
  23. "touser": wx_id,
  24. "msgtype": "text", # 本文
  25. "text": {
  26. "content": 'hello'
  27. }
  28. }
  29. r2 = requests.post(
  30. url="https://api.weixin.qq.com/cgi-bin/message/custom/send",
  31. params={
  32. 'access_token': access_token
  33. },
  34. # 发送的消息,必须是bytes类型
  35. data=bytes(json.dumps(body,ensure_ascii=False),encoding='utf-8')
  36. )
  37. print(r2.text)

解释:request,内部发送的数据是字节。默认格式为Latin-1,它不支持中文!

所以需要使用json序列化。如果发送的是字符串,它会使用Latin-1转码为bytes,遇到中文会报错

所以我这里,直接强转为bytes,那么它内部就不会转码了,直接发送!

执行脚本,输出:

  1. {"errcode":0,"errmsg":"ok"}

看状态,发送成功。

查看用户接收的消息

Day103 微信消息推送,结算中心业务流程 - 图9

发送模板消息

发送模板消息,脚本需要指定新的url

  1. https://api.weixin.qq.com/cgi-bin/message/template/send

默认这里是空的,点击新建测试模板

Day103 微信消息推送,结算中心业务流程 - 图10

注意:参数需以{{开头,以.DATA}}结尾。模板标题不能使用参数

这里的user,就是用户的微信名

Day103 微信消息推送,结算中心业务流程 - 图11

接下发送时,需要这个模板id

Day103 微信消息推送,结算中心业务流程 - 图12

修改test.py

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import json
  4. import requests
  5. # 1. 伪造浏览器向 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential... 发送GET请求,并获取token
  6. r1 = requests.get(
  7. url="https://api.weixin.qq.com/cgi-bin/token",
  8. params={
  9. "grant_type": "client_credential",
  10. "appid": 'wx038ba9d6c87fxxxx',
  11. "secret": 'fd1ebdff49010aa67a1457bbe250xxx',
  12. }
  13. )
  14. access_token = r1.json().get('access_token') # 获取token
  15. # print(access_token)
  16. # 2. 给指定用户发送普通消息消息:access_token/
  17. wx_id = 'oe0j758m-Zp4QBOvgzF8vGBCOxxx' # 微信号
  18. body = {
  19. "touser": wx_id,
  20. "template_id": 'OxCBr-98eVMkTLKb0ZGpLGK5mNnLMLoEZG2MsmR3Q_Q', # 模板id
  21. "data": {
  22. "user": {
  23. "value": "小明同学",
  24. "color": "#173177"
  25. }
  26. }
  27. }
  28. r2 = requests.post(
  29. url="https://api.weixin.qq.com/cgi-bin/message/template/send",
  30. params={
  31. 'access_token': access_token
  32. },
  33. data=json.dumps(body)
  34. )
  35. print(r2.text)

执行脚本,输出:

  1. {"errcode":0,"errmsg":"ok","msgid":412032057779486721}

查看手机消息

Day103 微信消息推送,结算中心业务流程 - 图13

推送消息,一天可以发送10万次

Day103 微信消息推送,结算中心业务流程 - 图14

这里演示的向用户发送推送消息,必须让用户关注公众号。从公众号后台的用户列表中,得到用户的微信号(随机字符串)

才可以准确发送到用户手机上,只有管理者,才能看到这个微信号

自动获取用户-消息发送

上面的脚本,演示的是手动发送。如果用户过多,发送消息会很繁琐!

如何让用户做简单的操作,就能自动发送消息给用户呢?

路飞学城购买课程之后,不能直接观看视频。要填写报名表才能观看!

填写相关信息后,发送微信消息

这里只做简单的功能:让用户扫描二维码,将微信号自动存储在数据库中,并发送消息

创建用户表

修改models.py

  1. from django.db import models
  2. class UserInfo(models.Model):
  3. name = models.CharField(max_length=32,verbose_name="用户名")
  4. pwd = models.CharField(max_length=64,verbose_name="密码")
  5. wx_id = models.CharField(max_length=32,null=True,blank=True,verbose_name="微信号")

执行2个命令,生成表

  1. python manage.py makemigrations
  2. python manage.py migrate

使用navicat打开sqlite3数据库

添加一条记录,微信号保持为空

Day103 微信消息推送,结算中心业务流程 - 图15

用户登录

修改urls.py,增加路径

  1. urlpatterns = [
  2. url(r'^admin/', admin.site.urls),
  3. url(r'^index/', views.index),
  4. url(r'^login/', views.login),
  5. ]

新建login.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <form method="post">
  9. {% csrf_token%}
  10. <input type="text" name="user">
  11. <input type="text" name="pwd">
  12. <input type="submit" value="提交">{{ msg }}
  13. </form>
  14. </body>
  15. </html>

修改views.py

  1. from django.shortcuts import render,HttpResponse,redirect
  2. from app01 import models
  3. # Create your views here.
  4. def login(request):
  5. """
  6. 用户登陆
  7. :param request:
  8. :return:
  9. """
  10. if request.method == 'GET':
  11. return render(request, 'login.html')
  12. user = request.POST.get('user')
  13. pwd = request.POST.get('pwd')
  14. obj = models.UserInfo.objects.filter(name=user, pwd=pwd).first()
  15. if obj:
  16. request.session['user_info'] = {'id': obj.id, 'name': obj.name}
  17. return redirect('/index/')
  18. return render(request, 'login.html', {'msg': '用户名或密码错误'})
  19. def index(request):
  20. """
  21. 首页
  22. :param request:
  23. :return:
  24. """
  25. return render(request,"index.html")

修改index.html,显示登录用户名

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>欢迎 {{ request.session.user_info.name }} 使用:路飞学城</h1>
  9. <h3>扫描关注路飞学诚(用于消息提示,请必须关注)</h3>
  10. <img style="width: 200px;" src="/static/0.jpg" alt="">
  11. </body>
  12. </html>

访问登录页面

Day103 微信消息推送,结算中心业务流程 - 图16

登录之后,效果如下:

Day103 微信消息推送,结算中心业务流程 - 图17

下一步,需要获取用户的微信号

怎么获取呢?让用户访问一个链接,执行上面的脚本,得到用户的微信号,并存入数据库!

js生成二维码

jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码。

如何使用它

将jquery.qrcode.min.js和jquery添加到您的网页中

  1. <script src="jquery.min.js"></script>
  2. <script type="text/javascript" src="jquery.qrcode.min.js"></script>

然后创建一个DOM元素去包含生成qr码。

  1. <div id="qrcode"></div>

最后你在此容器中的添加qrcode

  1. <script>
  2. jQuery(function(){
  3. jQuery('#qrcode').qrcode("http://www.jq22.com");
  4. })
  5. </script>

就这么简单,您想要的二维码就生成了。

在static目录中创建js目录,将3个文件jquery.min.js,jquery.qrcode.min.js,qrcode.js放到此目录

修改index.html,生成二维码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>欢迎 {{ request.session.user_info.name }} 使用:路飞学城</h1>
  9. <h3>扫描关注路飞学诚(用于消息提示,请必须关注)</h3>
  10. <img style="width: 200px;" src="/static/0.jpg" alt="">
  11. <script src="/static/js/jquery.min.js"></script>
  12. <script src="/static/js/jquery.qrcode.min.js"></script>
  13. <script src="/static/js/qrcode.js"></script>
  14. <script>
  15. $(function () {
  16. // empty()表示清空
  17. // text表示内容
  18. $('#qrcode').empty().qrcode({text: 'http://www.py3study.com/'});
  19. })
  20. </script>
  21. </body>
  22. </html>

刷新index页面,效果如下:

Day103 微信消息推送,结算中心业务流程 - 图18

用户扫描最下面的二维码,就会自动打开网页: http://www.py3study.com/

获取微信号并写入数据库

获取微信号,需要在这里配置回调的url,点击修改

Day103 微信消息推送,结算中心业务流程 - 图19

通过该接口,可以获取用户的基本信息(获取用户的OpenID是无需用户同意的,获取用户的基本信息则需用户同意)

这里必须公网IP才行

注意:冒号不能是中文!!!否则报url不匹配

Day103 微信消息推送,结算中心业务流程 - 图20

线上部署

登录到公网服务器,将项目拷贝过去

注意:python版本为3.5,django版本为1.11

安装requests

  1. pip3 install requests

修改urls.py,增加路径

  1. urlpatterns = [
  2. url(r'^admin/', admin.site.urls),
  3. url(r'^index/', views.index),
  4. url(r'^login/', views.login),
  5. url(r'^get_qrcode/', views.get_qrcode),
  6. url(r'^get_wx_id/', views.get_wx_id),
  7. ]

修改settings.py,运行所有IP访问

  1. ALLOWED_HOSTS = ['*',]

修改views.py,增加视图函数

注意:修改appid,secret改成自己的。redirect_uri改成自己的公网IP和端口

  1. from django.shortcuts import render, redirect
  2. from app01 import models
  3. from django.http import JsonResponse, HttpResponse
  4. # Create your views here.
  5. def login(request):
  6. """
  7. 用户登陆
  8. :param request:
  9. :return:
  10. """
  11. if request.method == 'GET':
  12. return render(request, 'login.html')
  13. user = request.POST.get('user')
  14. pwd = request.POST.get('pwd')
  15. obj = models.UserInfo.objects.filter(name=user, pwd=pwd).first()
  16. if obj:
  17. request.session['user_info'] = {'id': obj.id, 'name': obj.name}
  18. return redirect('/index/')
  19. return render(request, 'login.html', {'msg': '用户名或密码错误'})
  20. def index(request):
  21. """
  22. 首页
  23. :param request:
  24. :return:
  25. """
  26. return render(request, "index.html")
  27. def get_qrcode(request):
  28. """
  29. 访问获取用户基本信息接口
  30. 需要接收3个参数
  31. :param request:
  32. :return:
  33. """
  34. ret = {'status': True, 'data': None}
  35. # appid 是自己的appid
  36. # redirect_uri 是回调地址,腾讯服务器会访问它
  37. # state是自定义的,变量名可以随意
  38. access_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect"
  39. url = access_url.format(
  40. appid='wx038ba9d6c87fxxxx',
  41. redirect_uri="http://45.xx.192.14:8000/get_wx_id/", # 跳转会我的网站
  42. state=request.session['user_info']['id'] # 用户ID
  43. )
  44. ret['data'] = url # 生成url
  45. return JsonResponse(ret) # 返回给ajax
  46. def get_wx_id(request):
  47. """
  48. 获取微信ID,并更新到数据库
  49. :param request:
  50. :return:
  51. """
  52. import requests
  53. code = request.GET.get("code")
  54. state = request.GET.get("state")
  55. # 获取该用户openId(用户唯一,用于给用户发送消息)
  56. r1 = requests.get(
  57. url="https://api.weixin.qq.com/sns/oauth2/access_token",
  58. params={
  59. "appid": 'wx038ba9d6c87fxxxx',
  60. "secret": 'fd1ebdff49010aa67a1457bbe250xxxx',
  61. "code": code,
  62. "grant_type": 'authorization_code',
  63. }
  64. ).json()
  65. # 获取的到openid表示用户授权成功
  66. wx_id = r1.get("openid")
  67. user = models.UserInfo.objects.filter(id=state).first()
  68. # 判断用户id不为空
  69. if not user.wx_id:
  70. user.wx_id = wx_id
  71. user.save() # 修改微信id
  72. return HttpResponse('授权成功')

修改index.html,增加ajax

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>欢迎 {{ request.session.user_info.name }} 使用:路飞学城</h1>
  9. <h3>扫描关注路飞学诚(用于消息提示,请必须关注)</h3>
  10. <img style="width: 250px;" src="/static/0.jpg" alt="">
  11. <h3>下一步:请将微信ID发给我</h3>
  12. <div id="qrcode" style="width: 250px;height: 250px;background-color: white;">
  13. </div>
  14. <script src="/static/js/jquery.min.js"></script>
  15. <script src="/static/js/jquery.qrcode.min.js"></script>
  16. <script src="/static/js/qrcode.js"></script>
  17. <script>
  18. $(function () {
  19. get_qcode();
  20. });
  21. function get_qcode() {
  22. $.ajax({
  23. url: '/get_qrcode/',
  24. type: 'GET',
  25. dataType: 'JSON',
  26. success: function (arg) {
  27. //arg.data 就是访问获取用户基本信息接口的url地址
  28. // 需要接收3个参数
  29. $('#qrcode').empty().qrcode({text: arg.data});
  30. console.log(arg.data);
  31. }
  32. })
  33. }
  34. </script>
  35. </body>
  36. </html>

访问公网的登录地址

Day103 微信消息推送,结算中心业务流程 - 图21

登录成功后,进入首页

Day103 微信消息推送,结算中心业务流程 - 图22

可以发现最下面的二维码,更加复杂了。因为里面加了很长的url

查看console

Day103 微信消息推送,结算中心业务流程 - 图23

使用手机扫描二维码,它其实就是访问上面很长的url

点击允许

Day103 微信消息推送,结算中心业务流程 - 图24

点击继续访问

Day103 微信消息推送,结算中心业务流程 - 图25

提示授权成功

Day103 微信消息推送,结算中心业务流程 - 图26

查看服务器的终端输出

它先访问的是get_qrcode

get_wx_id是腾讯访问的

Day103 微信消息推送,结算中心业务流程 - 图27

将sqlite3下载下来,使用navicat查看数据库

发现微信id更新了

Day103 微信消息推送,结算中心业务流程 - 图28

网页点击发送消息

单独做一个页面,点击指定的用户,发送消息

修改urls.py,增加路径

  1. urlpatterns = [
  2. url(r'^admin/', admin.site.urls),
  3. url(r'^index/', views.index),
  4. url(r'^login/', views.login),
  5. url(r'^get_qrcode/', views.get_qrcode),
  6. url(r'^get_wx_id/', views.get_wx_id),
  7. url(r'^send/', views.send),
  8. url(r'^send_msg/', views.send_msg),
  9. ]

修改views.py

  1. from django.shortcuts import render,redirect
  2. from app01 import models
  3. from django.http import JsonResponse, HttpResponse
  4. # Create your views here.
  5. def login(request):
  6. """
  7. 用户登陆
  8. :param request:
  9. :return:
  10. """
  11. if request.method == 'GET':
  12. return render(request, 'login.html')
  13. user = request.POST.get('user')
  14. pwd = request.POST.get('pwd')
  15. obj = models.UserInfo.objects.filter(name=user, pwd=pwd).first()
  16. if obj:
  17. request.session['user_info'] = {'id': obj.id, 'name': obj.name}
  18. return redirect('/index/')
  19. return render(request, 'login.html', {'msg': '用户名或密码错误'})
  20. def index(request):
  21. """
  22. 首页
  23. :param request:
  24. :return:
  25. """
  26. return render(request,"index.html")
  27. def get_qrcode(request):
  28. """
  29. 访问获取用户基本信息接口
  30. 需要接收3个参数
  31. :param request:
  32. :return:
  33. """
  34. ret = {'status': True, 'data': None}
  35. # appid 是自己的appid
  36. # redirect_uri 是回调地址,腾讯服务器会访问它
  37. # state是自定义的,变量名可以随意
  38. access_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect"
  39. url = access_url.format(
  40. appid='wx038ba9d6c87fxxxx',
  41. redirect_uri="http://45.xx.192.14:8000/get_wx_id/", # 跳转会我的网站
  42. state=request.session['user_info']['id'] # 用户ID
  43. )
  44. ret['data'] = url # 生成url
  45. return JsonResponse(ret) # 返回给ajax
  46. def get_wx_id(request):
  47. """
  48. 获取微信ID,并更新到数据库
  49. :param request:
  50. :return:
  51. """
  52. import requests
  53. code = request.GET.get("code")
  54. state = request.GET.get("state")
  55. # 获取该用户openId(用户唯一,用于给用户发送消息)
  56. r1 = requests.get(
  57. url="https://api.weixin.qq.com/sns/oauth2/access_token",
  58. params={
  59. "appid": 'wx038ba9d6c87fxxxx',
  60. "secret": 'fd1ebdff49010aa67a1457bbe250xxxx',
  61. "code": code,
  62. "grant_type": 'authorization_code',
  63. }
  64. ).json()
  65. # 获取的到openid表示用户授权成功
  66. wx_id = r1.get("openid")
  67. user = models.UserInfo.objects.filter(id=state).first()
  68. # 判断用户id不为空
  69. if not user.wx_id:
  70. user.wx_id = wx_id
  71. user.save() # 修改微信id
  72. return HttpResponse('授权成功')
  73. def send(request):
  74. """
  75. 发送消息
  76. :param request:
  77. :return:
  78. """
  79. user_list = models.UserInfo.objects.all()
  80. return render(request, 'send.html', {'user_list': user_list})
  81. def send_msg(request):
  82. """
  83. 发送消息
  84. :param request:
  85. :return:
  86. """
  87. id = request.session['user_info']['id']
  88. obj = models.UserInfo.objects.filter(id=id).first()
  89. import json
  90. import requests
  91. # 1. 伪造浏览器向 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential... 发送GET请求,并获取token
  92. r1 = requests.get(
  93. url="https://api.weixin.qq.com/cgi-bin/token",
  94. params={
  95. "grant_type": "client_credential",
  96. "appid": 'wx038ba9d6c87fxxxx',
  97. "secret": 'fd1ebdff49010aa67a1457bbe250xxxx',
  98. }
  99. )
  100. access_token = r1.json().get('access_token')
  101. body = {
  102. "touser": obj.wx_id,
  103. "template_id": 'OxCBr-98eVMkTLKb0ZGpLGK5mNnLMLoEZG2MsmR3Q_Q',
  104. "data": {
  105. "user": {
  106. "value": "Hello Kitty",
  107. "color": "#173177"
  108. }
  109. }
  110. }
  111. r2 = requests.post(
  112. url="https://api.weixin.qq.com/cgi-bin/message/template/send",
  113. params={
  114. 'access_token': access_token
  115. },
  116. data=json.dumps(body)
  117. )
  118. print(r2.text)
  119. return HttpResponse('发送成功')

创建send.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% for item in user_list %}
        <li>{{ item.name }} {{ item.wx_id }}   <a href="/send_msg/">发送消息</a></li>
        {% endfor %}
    </ul>
</body>
</html>

访问页面,点击发送消息

Day103 微信消息推送,结算中心业务流程 - 图29

提示发送成功

Day103 微信消息推送,结算中心业务流程 - 图30

查看手机信息

Day103 微信消息推送,结算中心业务流程 - 图31

流程图

Day103 微信消息推送,结算中心业务流程 - 图32

解释:

  1. 浏览器访问服务器的登录页面
  2. 服务器返回登录成功,跳转首页。并生成底部的二维码,链接就是获取个人信息的
  3. 用户扫描二维码,关注公众号
  4. 引导用户进入授权页面同意授权,用户扫描下面的二维码
  5. 用户手机访问链接,用来获取微信个人信息的
  6. 微信服务器获取个人信息,访问回调地址redirect_uri,也就是个人服务器。
  7. 个人服务器访问微信服务器,通过code换取网页授权access_token(与基础支持中的access_token不同)
  8. 微信服务器将个人信息返回给服务器,服务器更新数据库

总结:

a.路飞中使用的是已认证的服务号

b.基于微信ID发送消息
    - 获取AccessToken
    - 发送消息:
        - AccessToken
        - 微信ID
        - 消息内容
    注意:AccessToken的超时时间8小时

c.诱导用户发送微信ID"间接"给我

步骤:
1. 申请沙箱环境账号

2. 手动发送消息

3. 写django程序:
- 创建用户表:wx_id
    - 登陆页面
    - "填写报名报" 扫码
    - 公众号
        - 授权码,基于qrcode.js库完成+ajax从后台获取的要跳转的地址(腾讯)
        - 公众号后台设置:网页授权获取用户基本信息  -->  xx.xx.xx.xx:8000
        - redirect_uri指定要要跳转的地址

4. - 回调函数,从腾讯中获取用户微信ID并更新到自己数据库
    - 获取微信ID,并更新到数据库
        - 获取该用户openId
        - 获取的到openid表示用户授权成功
        - 更新数据库
5.页面发送
    - 用户列表
    - 要发送的内容
    - 按钮:发送
        - 1. 伪造浏览器向公众号发送GET请求,并获取token
        - 2. 给指定用户发送普通消息消息
        - 3. 给指定用户发送模板消息

将appid,secretredirect_uri 移植到settings.py中

完整代码请参考github

https://github.com/987334176/WeChat

二、结算中心业务流程

购物车3个状态:放入购物车,结算,支付

结算页面

Day103 微信消息推送,结算中心业务流程 - 图33

进入结算页面,购物车不会清空。只有支付成功后,才会删除购物车的商品!

结算中心和购物车一样,是一个中间状态,可以删除/修改价格策略

它比购物车,多了一个字段—>优惠券

优惠券这里面涉及的逻辑,就比较复杂了

由于时间关系,没法一一细说。

直接上表结构

下载最后一个版本的代码

https://github.com/987334176/luffycity/archive/v1.5.zip

修改models.py,增加3个表。注意:course要开启优惠券

完整代码如下:

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.utils.safestring import mark_safe
from django.db import models
import hashlib


# ######################## 课程相关 ########################

class CourseCategory(models.Model):
    """课程大类, e.g 前端  后端..."""
    name = models.CharField(max_length=64, unique=True)

    def __str__(self):
        return "%s" % self.name

    class Meta:
        verbose_name_plural = "01.课程大类"


class CourseSubCategory(models.Model):
    """课程子类, e.g python linux """
    category = models.ForeignKey("CourseCategory")
    name = models.CharField(max_length=64, unique=True)

    def __str__(self):
        return "%s" % self.name

    class Meta:
        verbose_name_plural = "02.课程子类"


class DegreeCourse(models.Model):
    """学位课程"""
    name = models.CharField(max_length=128, unique=True)
    course_img = models.CharField(max_length=255, verbose_name="缩略图")
    brief = models.TextField(verbose_name="学位课程简介", )
    total_scholarship = models.PositiveIntegerField(verbose_name="总奖学金(贝里)", default=40000)  # 2000 2000
    mentor_compensation_bonus = models.PositiveIntegerField(verbose_name="本课程的导师辅导费用(贝里)", default=15000)
    period = models.PositiveIntegerField(verbose_name="建议学习周期(days)", default=150)  # 为了计算学位奖学金
    prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
    teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")

    # 用于GenericForeignKey反向查询, 不会生成表字段,切勿删除
    # coupon = GenericRelation("Coupon")

    # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
    degreecourse_price_policy = GenericRelation("PricePolicy")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = "03.学位课"


class Teacher(models.Model):
    """讲师、导师表"""
    name = models.CharField(max_length=32)
    role_choices = ((0, '讲师'), (1, '导师'))
    role = models.SmallIntegerField(choices=role_choices, default=0)
    title = models.CharField(max_length=64, verbose_name="职位、职称")
    signature = models.CharField(max_length=255, help_text="导师签名", blank=True, null=True)
    image = models.CharField(max_length=128)
    brief = models.TextField(max_length=1024)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = "04.导师或讲师"


class Scholarship(models.Model):
    """学位课程奖学金"""
    degree_course = models.ForeignKey("DegreeCourse")
    time_percent = models.PositiveSmallIntegerField(verbose_name="奖励档位(时间百分比)", help_text="只填百分值,如80,代表80%")
    value = models.PositiveIntegerField(verbose_name="奖学金数额")

    def __str__(self):
        return "%s:%s" % (self.degree_course, self.value)

    class Meta:
        verbose_name_plural = "05.学位课奖学金"


class Course(models.Model):
    """专题课/学位课模块表"""
    name = models.CharField(max_length=128, unique=True)
    course_img = models.CharField(max_length=255)
    sub_category = models.ForeignKey("CourseSubCategory")
    course_type_choices = ((0, '付费'), (1, 'VIP专享'), (2, '学位课程'))
    course_type = models.SmallIntegerField(choices=course_type_choices)

    # 不为空;学位课的某个模块
    # 为空;专题课
    degree_course = models.ForeignKey("DegreeCourse", blank=True, null=True, help_text="若是学位课程,此处关联学位表")

    brief = models.TextField(verbose_name="课程概述", max_length=2048)
    level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
    level = models.SmallIntegerField(choices=level_choices, default=1)
    pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)
    period = models.PositiveIntegerField(verbose_name="建议学习周期(days)", default=7)  #
    order = models.IntegerField("课程顺序", help_text="从上一个课程数字往后排")
    attachment_path = models.CharField(max_length=128, verbose_name="课件路径", blank=True, null=True)
    status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
    status = models.SmallIntegerField(choices=status_choices, default=0)
    template_id = models.SmallIntegerField("前端模板id", default=1)

    coupon = GenericRelation("Coupon")

    # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
    price_policy = GenericRelation("PricePolicy")

    asked_question = GenericRelation("OftenAskedQuestion")


    def __str__(self):
        return "%s(%s)" % (self.name, self.get_course_type_display())


    def save(self, *args, **kwargs):
        if self.course_type == 2:
            if not self.degree_course:
                raise ValueError("学位课程必须关联对应的学位表")
        super(Course, self).save(*args, **kwargs)


    class Meta:
        verbose_name_plural = "06.专题课或学位课模块"


class CourseDetail(models.Model):
    """课程详情页内容"""
    course = models.OneToOneField("Course")
    hours = models.IntegerField("课时")
    course_slogan = models.CharField(max_length=125, blank=True, null=True)
    video_brief_link = models.CharField(verbose_name='课程介绍', max_length=255, blank=True, null=True)
    why_study = models.TextField(verbose_name="为什么学习这门课程")
    what_to_study_brief = models.TextField(verbose_name="我将学到哪些内容")
    career_improvement = models.TextField(verbose_name="此项目如何有助于我的职业生涯")
    prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
    recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)
    teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")

    def __str__(self):
        return "%s" % self.course

    class Meta:
        verbose_name_plural = "07.课程或学位模块详细"


class OftenAskedQuestion(models.Model):
    """常见问题"""
    content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    question = models.CharField(max_length=255)
    answer = models.TextField(max_length=1024)


    def __str__(self):
        return "%s-%s" % (self.content_object, self.question)


    class Meta:
        unique_together = ('content_type', 'object_id', 'question')
        verbose_name_plural = "08. 常见问题"


class CourseOutline(models.Model):
    """课程大纲"""
    course_detail = models.ForeignKey("CourseDetail")
    title = models.CharField(max_length=128)
    # 前端显示顺序
    order = models.PositiveSmallIntegerField(default=1)

    content = models.TextField("内容", max_length=2048)

    def __str__(self):
        return "%s" % self.title

    class Meta:
        unique_together = ('course_detail', 'title')
        verbose_name_plural = "09. 课程大纲"


class CourseChapter(models.Model):
    """课程章节"""
    course = models.ForeignKey("Course")
    chapter = models.SmallIntegerField(verbose_name="第几章", default=1)
    name = models.CharField(max_length=128)
    summary = models.TextField(verbose_name="章节介绍", blank=True, null=True)
    pub_date = models.DateField(verbose_name="发布日期", auto_now_add=True)

    class Meta:
        unique_together = ("course", 'chapter')
        verbose_name_plural = "10. 课程章节"

    def __str__(self):
        return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)


class CourseSection(models.Model):
    """课时目录"""
    chapter = models.ForeignKey("CourseChapter")
    name = models.CharField(max_length=128)
    order = models.PositiveSmallIntegerField(verbose_name="课时排序", help_text="建议每个课时之间空1至2个值,以备后续插入课时")
    section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))
    section_type = models.SmallIntegerField(default=2, choices=section_type_choices)
    section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文档,填link")
    video_time = models.CharField(verbose_name="视频时长", blank=True, null=True, max_length=32)  # 仅在前端展示使用
    pub_date = models.DateTimeField(verbose_name="发布时间", auto_now_add=True)
    free_trail = models.BooleanField("是否可试看", default=False)

    class Meta:
        unique_together = ('chapter', 'section_link')
        verbose_name_plural = "11. 课时"

    def __str__(self):
        return "%s-%s" % (self.chapter, self.name)


class Homework(models.Model):
    chapter = models.ForeignKey("CourseChapter")
    title = models.CharField(max_length=128, verbose_name="作业题目")
    order = models.PositiveSmallIntegerField("作业顺序", help_text="同一课程的每个作业之前的order值间隔1-2个数")
    homework_type_choices = ((0, '作业'), (1, '模块通关考核'))
    homework_type = models.SmallIntegerField(choices=homework_type_choices, default=0)
    requirement = models.TextField(max_length=1024, verbose_name="作业需求")
    threshold = models.TextField(max_length=1024, verbose_name="踩分点")
    recommend_period = models.PositiveSmallIntegerField("推荐完成周期(天)", default=7)
    scholarship_value = models.PositiveSmallIntegerField("为该作业分配的奖学金(贝里)")
    note = models.TextField(blank=True, null=True)
    enabled = models.BooleanField(default=True, help_text="本作业如果后期不需要了,不想让学员看到,可以设置为False")

    class Meta:
        unique_together = ("chapter", "title")
        verbose_name_plural = "12. 章节作业"

    def __str__(self):
        return "%s - %s" % (self.chapter, self.title)


# class CourseReview(models.Model):
#     """课程评价"""
#     enrolled_course = models.OneToOneField("EnrolledCourse")
#     about_teacher = models.FloatField(default=0, verbose_name="讲师讲解是否清晰")
#     about_video = models.FloatField(default=0, verbose_name="内容实用")
#     about_course = models.FloatField(default=0, verbose_name="课程内容通俗易懂")
#     review = models.TextField(max_length=1024, verbose_name="评价")
#     disagree_number = models.IntegerField(default=0, verbose_name="踩")
#     agree_number = models.IntegerField(default=0, verbose_name="赞同数")
#     tags = models.ManyToManyField("Tags", blank=True, verbose_name="标签")
#     date = models.DateTimeField(auto_now_add=True, verbose_name="评价日期")
#     is_recommend = models.BooleanField("热评推荐", default=False)
#     hide = models.BooleanField("不在前端页面显示此条评价", default=False)
#
#     def __str__(self):
#         return "%s-%s" % (self.enrolled_course.course, self.review)
#
#     class Meta:
#         verbose_name_plural = "13. 课程评价(购买课程后才能评价)"
#
#
# class DegreeCourseReview(models.Model):
#     """学位课程评价
#     为了以后可以定制单独的评价内容,所以不与普通课程的评价混在一起,单独建表
#     """
#     enrolled_course = models.ForeignKey("EnrolledDegreeCourse")
#     course = models.ForeignKey("Course", verbose_name="评价学位模块", blank=True, null=True,
#                                help_text="不填写即代表评价整个学位课程", limit_choices_to={'course_type': 2})
#     about_teacher = models.FloatField(default=0, verbose_name="讲师讲解是否清晰")
#     about_video = models.FloatField(default=0, verbose_name="视频质量")
#     about_course = models.FloatField(default=0, verbose_name="课程")
#     review = models.TextField(max_length=1024, verbose_name="评价")
#     disagree_number = models.IntegerField(default=0, verbose_name="踩")
#     agree_number = models.IntegerField(default=0, verbose_name="赞同数")
#     tags = models.ManyToManyField("Tags", blank=True, verbose_name="标签")
#     date = models.DateTimeField(auto_now_add=True, verbose_name="评价日期")
#     is_recommend = models.BooleanField("热评推荐", default=False)
#     hide = models.BooleanField("不在前端页面显示此条评价", default=False)
#
#     def __str__(self):
#         return "%s-%s" % (self.enrolled_course, self.review)
#
#     class Meta:
#         verbose_name_plural = "14. 学位课评价(购买课程后才能评价)"


class PricePolicy(models.Model):
    """价格与有课程效期表"""
    content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    # course = models.ForeignKey("Course")
    valid_period_choices = ((1, '1天'), (3, '3天'),
                            (7, '1周'), (14, '2周'),
                            (30, '1个月'),
                            (60, '2个月'),
                            (90, '3个月'),
                            (180, '6个月'), (210, '12个月'),
                            (540, '18个月'), (720, '24个月'),
                            )
    valid_period = models.SmallIntegerField(choices=valid_period_choices)
    price = models.FloatField()

    class Meta:
        unique_together = ("content_type", 'object_id', "valid_period")
        verbose_name_plural = "15. 价格策略"

    def __str__(self):
        return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)


# ################################### 优惠券相关 #################################

class Coupon(models.Model):
    """优惠券生成规则"""
    name = models.CharField(max_length=64, verbose_name="活动名称")
    brief = models.TextField(blank=True, null=True, verbose_name="优惠券介绍")

    coupon_type_choices = ((0, '立减'), (1, '满减券'), (2, '折扣券'))
    coupon_type = models.SmallIntegerField(choices=coupon_type_choices, default=0, verbose_name="券类型")

    money_equivalent_value = models.IntegerField(verbose_name="等值货币")
    off_percent = models.PositiveSmallIntegerField("折扣百分比", help_text="只针对折扣券,例7.9折,写79", blank=True, null=True)
    minimum_consume = models.PositiveIntegerField("最低消费", default=0, help_text="仅在满减券时填写此字段")

    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    object_id = models.PositiveIntegerField("绑定课程", blank=True, null=True, help_text="可以把优惠券跟课程绑定")
    content_object = GenericForeignKey('content_type', 'object_id')

    quantity = models.PositiveIntegerField("数量(张)", default=1)
    open_date = models.DateField("优惠券领取开始时间")
    close_date = models.DateField("优惠券领取结束时间")
    valid_begin_date = models.DateField(verbose_name="有效期开始时间", blank=True, null=True)
    valid_end_date = models.DateField(verbose_name="有效结束时间", blank=True, null=True)
    # coupon_valid_days = models.PositiveIntegerField(verbose_name="优惠券有效期(天)", blank=True, null=True,
    #                                                 help_text="自券被领时开始算起")
    date = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = "31. 优惠券生成记录"

    def __str__(self):
        return "%s(%s)" % (self.get_coupon_type_display(), self.name)


class CouponRecord(models.Model):
    """优惠券发放、消费纪录"""
    coupon = models.ForeignKey("Coupon")
    account = models.ForeignKey("Account", verbose_name="拥有者")

    number = models.CharField(max_length=64, unique=True)

    status_choices = ((0, '未使用'), (1, '已使用'), (2, '已过期'))
    status = models.SmallIntegerField(choices=status_choices, default=0)

    get_time = models.DateTimeField(verbose_name="领取时间", help_text="用户领取时间")


    used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用时间")

    # order = models.ForeignKey("Order", blank=True, null=True, verbose_name="关联订单")  # 一个订单可以有多个优惠券
    order_id = models.IntegerField(verbose_name='关联订单ID')


    class Meta:
        verbose_name_plural = "32. 用户优惠券"

    def __str__(self):
        return '%s-%s-%s' % (self.account, self.number, self.status)


class Account(models.Model):
    username = models.CharField("用户名", max_length=64, unique=True)
    email = models.EmailField(
        verbose_name='邮箱',
        max_length=255,
        unique=True,
        blank=True,
        null=True
    )
    password = models.CharField('密码', max_length=128)

    class Meta:
        verbose_name_plural = "33. 用户表"

执行2个命令,生成表

python manage.py makemigrations
python manage.py migrate

录入几条数据

作业

考试题(Python基础)

1. 写代码实现:val = “i am a string”,实现⼀个⽅法,将字符串逆序输出(2分)

val = "i am a string"
def func(st):
    return st[::-1]

print(func(val))

执行输出: gnirts a ma i

2. 判断101-200之间有多少个质数(2分)

提示:⼀个⼤于1的⾃然数,除了1和它⾃身外,不能被其他⾃然数整除的书叫质数 循环加判断,取余数为0

L1 = []

for x in range(101, 200):
    n = 0
    for y in range(1, x + 1):
        if x % y == 0:
            n = n + 1

    if n == 2:
        # print(x)
        L1.append(x)

print(L1)

执行输出:

[101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]

3. 简述正则表达式中的贪婪匹配并举例说明(2分)

贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如下面使用模式p匹配字符串str,结果就是匹配到:abcaxc(ab*c)。
如:String str="abcaxc";

    Patter p="ab*c";

4. 写代码(3分)

v1 = {11,22,33}

v2 = {22,44,55}

a. 如何获取 v1 中存在⽽v2中不存在的值?

b. 如何获取 v2 中存在⽽v2中不存在的值?

c. 如何获取v1和v2中都存在的值?

print(v1-v2)  # 差集
print(v2-v1)  # 差集
print(v1.intersection(v2))  # 交集

5. 请编写⼀个函数实现将IP地址转换成⼀个整数(4分)

如 10.3.9.12 转换规则为: 10 00001010 3 00000011 9 00001001 12 00001100 再将以上⼆进制拼接起来计算⼗进制结果,即: 00001010 00000011 00001001 00001100 = ?

def func(args):
    st = ''
    for i in args:
        new_i = bin(i)  # 将数字转化为二进制
        new_i = new_i[2:]  # 将转化后的二进制去除'0b'前缀
        new_i = new_i[2:].rjust(8, '0')  # 二进制前面填充0,固定总长度8
        st += new_i[2:].rjust(8, '0')  # 将四个数字的二进制进行拼接
    st = int(st, base=2)  # 拼接后的字符串转化为10进制数字
    return st


li = [10, 3, 9, 12]
print(func(li))

执行输出:33554688

ORM查询

获取用户ID=1的所有优惠券

obj = models.Account.objects.filter(id=1).first()
    for i in obj.couponrecord_set.all():
        print(i.coupon.id,i.coupon.get_coupon_type_display(),i.coupon.off_percent)

获取专题课ID=1且用户ID=10的所有优惠券

obj1 = models.Course.objects.filter(id=1).first()
    print(obj1.coupon.all())
    for i in obj1.coupon.all():
        print(i)

获取用户ID=10的所有未绑定课程的优惠券

obj2 = models.CouponRecord.objects.filter(account=1,coupon__object_id__isnull=False)
    for i in obj2:
        print(i.coupon.id,i.coupon.get_coupon_type_display(),i.coupon.off_percent)

获取用户ID=1的所有可用优惠券

obj3 = models.CouponRecord.objects.filter(status=0,account_id=1)
    for i in obj3:
        print(i.coupon.id,i.coupon.get_coupon_type_display(),i.coupon.off_percent)