2021-08-31

微信小程序+Django+DRF个人笔记

跳转

对标签绑定点击事件

<view class="item" bindtap="onclick" data-nid="123">

其中bindtap为点击事件,onclick为点击后js执行的函数,使用data-参数名 来传参;

js响应函数

onclick:function(e){
    var nid=e.currentTarget.dataset.nid;
  console.log(nid);
  }

其中e为一个对象,可以通过下层的currentTarget下的dataset就可以找到需要传递的参数

e的层次代码图如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTWR4Jkl-1630375528307)(./代码截图/e事件.png)]

页面跳转

只需要在响应函数内添加如下代码,另外需要注意跳转页面不能是设置过tabbar的页面:

 wx.navigateTo({
      url: '/pages/redired/redired',
    })

如果需要用到拼接的方式获取页面路径则可以使用如下方式:

  wx.navigateTo({
      url: '/pages/redired/redired?id='+nid,
    })

页面跳转可以接受参数,在跳转到的页面中的onload函数中接受

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log(options);
  },

通过标签跳转

<navigator url="/pages/redired/redired?id=666">跳转到新页面</navigator>

#数据绑定
前端中vue.js的绑定格式


<div id="app">
  <p> {{ counter }}</p>
</div>

<script>
    new Vue({
        el: '#app',
        data: {
            counter: 0
        }
    })
</script>

微信的数据绑定和前端一样,如下面例子

<view>数据:{{message}}</view>

/**
* 页面的初始数据
*/
data: {
message:"这里是数据双向绑定"
},

通过函数获取data中的message,this指当前的page

ChangeData:function(){
    console.log(this.data.message);
  },

修改数据:使用setData函数

  ChangeData:function(){
    //获取数据
    console.log(this.data.message);
    //修改数据(错误,这里改变后端的值)
    //this.data.message="这里是message"
    this.setData({message:"修改成功数据"})
    console.log(this.data.message);
  },

获取用户信息

如果只是展示用户头像昵称,可以使用 组件

<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName"></open-data>

需要使用 button 来授权登录

<button wx:if="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">授权登录</button>
<view wx:else>请升级微信版本</view>
Page({
  data: {
    canIUse: wx.canIUse('button.open-type.getUserInfo')
  },
  onLoad: function() {
    // 查看是否授权
    wx.getSetting({
      success (res){
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称
          wx.getUserInfo({
            success: function(res) {
              console.log(res.userInfo)
            }
          })
        }
      }
    })
  },
  bindGetUserInfo (e) {
    console.log(e.detail.userInfo)//获取具体信息使用字典['key']
  }
})

获取定位信息

这里的 that=this 是将page引入到该函数中,不然下面的函数中的this不是指向page。

  getLocalPath:function(){
    var that=this
    wx.chooseLocation({
      success:function(res){
      console.log(res.address)
      that.setData({localpath:res.address})
      }
    })
  },

for指令

####循环的是列表

<text>商品列表</text>
<view>
  <view wx:for="{{datalist}}">{{index}}-{{item}}</view>
</view>
 data: {
    datalist:['袜子','鞋子','衣服','华为','小米']
  },

其中item和index是死的,不能乱改,但是可以采用下面的形式来修改

<text>商品列表</text>
<view>
  <view wx:for="{{datalist}}" wx:for-index="idx" wx:for-item="x">{{idx}}-{{x}}</view>
</view>

####循环的是字典

<view>用户信息(循环字典)</view>

<view>
<view>{{userinfo.name}}</view>
<view>{{userinfo.age}}</view>
</view>

<view wx:for="{{userinfo}}">{{index}}-{{item}}</view>
 data: {
    datalist:['袜子','鞋子','衣服','华为','小米'],
    userinfo:{
      name:'小青',
      age:'19'
    }
  },

上传图片

<text bindtap="upLoadImage">请上传头像</text>
<view>
<image wx:for="{{piclist}}" src="{{item}}"></image>
</view>
 data: {
    piclist:['../image/head.jpg','../image/算法图.jpg']
  },
  upLoadImage:function(){ 
    var that=this
    wx.chooseImage({
      count:9,//最多选择9张图片
      sizeType:['original', 'compressed'],//原图;压缩图
      sourceType:['album', 'camera'],//选择相册和相机

      success:function(res){//成功后
        console.log(res)
        that.setData({piclist: res.tempFilePaths})
      },

      fail:function(res){//失败后
      },
      complete:function(res){//无论成功失败都执行

      }
    });
  },

上传图片追加的方式

     success:function(res){//成功后
       var newlist=that.data.piclist.concat(res.tempFilePaths);//concat将两个列表合并,但是不改变原来列表的值,他们重新复制给新的列表
       that.setData({piclist:newlist})
      },

数据绑定(双向绑定)

input的双向绑定

<text>你输入了:{{message}}</text>
<input value="{{message}}" bindinput="bindText"></input>
 data: {
    message:"你好"
  },
  bindText:function(e){
    console.log(e.detail.value)
    this.setData({message:e.detail.value})
  },

登录(前后端)

<text>手机号</text>
<input value="{{phone}}" bindinput="bindText" placeholder="请输入手机号"></input>
<text>验证码: <text>点击获取验证码</text></text>
<input value="{{code}}" bindinput="bindCode" placeholder="请输入验证码"></input>

<button bindtap="login">登录</button>

js请求部分

 data: {
    phone:"",
    code:'',
  },
  /*获取并且设置输入的phone*/ 
  bindText:function(e){
    console.log(e.detail.value)
    this.setData({phone:e.detail.value})
  },
  /**获取并且设置code */
  bindCode:function(e){
    console.log(e.detail.value)
    this.setData({code:e.detail.value})
  },
  /**登录 */
  login:function(){
    console.log(this.data.phone,this.data.code)
    /**将手机号和验证码发送到后端,后端进行登录 */
   wx.request({
     url: 'http://127.0.0.1:8000/app01/login/',
     data: {phone:this.data.phone,code:this.data.code},
     method: 'POST',
     success: (result) => {console.log(result);},
      
   })
  },

在使用 wx.request等网络请求的时候,需要遵循:

  • 网络地址为https
  • 后台必须设置需要访问的域名

后端api设置

  • 新建django项目
  • 路由分发urls
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/',include('app01.urls'))
]

  • 新建app01
  • cbv实现简单返回
from django.shortcuts import render,HttpResponse,redirect
from rest_framework.views import APIView
from rest_framework.response import Response

class LoginView(APIView):
    def post(self,request,*args,**kwargs):
        print(request.data)
        return Response({'status':True})
    def get(self,request):
        print(request.data)
        return Response({"status":201})  
  • 在app01新建urls.py
from django.contrib import admin
from django.urls import path,include
from app01 import views
urlpatterns = [

    path('login/',views.LoginView.as_view())
]
  • 实验连接

手机号格式验证

使用toast和re

 if(this.data.phone.length!=11){
      wx.showToast({
        title: '手机号长度错误',
        icon:"none"/*loading success none error 支持插图片*/
      })
      return;
    }
  //正则匹配手机格式
    var reg=/^(1[3|4|7|8|9]\d(9)$)/;
   if( !reg.test(this.data.phone)){
     wx.showToast({
       title: '手机号格式错误',
       icon:"none"
     })
     return;
   }

验证手机号

正则 序列化 cbv redis 腾讯云短信验证

from django.shortcuts import render,HttpResponse,redirect
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
import re


def phone_validator(value):

    if not re.match(r'^1[3|4|5|7|8][0-9]{9}$',value):
        raise ValidationError('手机格式错误')

class MessageSerializer(serializers.Serializer):
    phone=serializers.CharField(label="手机号",validators=[phone_validator,])


class MessageView(APIView):
    def get(self,request,*args,**kwargs):
        #1.获取手机号
        #2.手机格式校验  序列化
        ser=MessageSerializer(data=request.query_params)
        if not ser.is_valid():
            return Response({"status":False,'message':'手机号格式错误'})
        phone=ser.validated_data.get('phone')
        #3.生成随机验证码
        import random
        random_code=random.randint(1000,9999)
        #4.发送到手机上,购买服务器发送短信,阿里云/腾讯云
        '''
        注册腾讯云开通短信服务
        创建应用
            sdk appid:1400555798
        申请签名 使用公众号
        签名管理 id 名称
        申请模板 id 名称
        申请腾讯云的appid secrect key
        调用相关接口去发送短信 sdk 写好相关
        '''
        #TODO tencent.send_message.get(phone,random_code)
        #5.校验验证码和手机号保留起来,超时时间为(30s过期)
        # 5.1 搭建redis服务器
        #5.2 diango中安装方便使用redis的模块django-redis
            #配置:setting.py
        '''
        import redis
        pool=redis.ConnectionPool(host='127.0.0.1',port=8000)
        conn=redis.Redis(connection_pool=pool)
        conn.set(phone,random_code,ex=30)
       '''
        from django_redis import get_redis_connection
        coon=get_redis_connection()
        coon.set(phone,random_code,ex=30)

        # redis coon.set('19187495242','1675',ex=30)
        #conn=conn.get('19187495242')

        return Response({"status":True,'message':'发送成功'})

使用邮箱了

  • redis
    在settings.py中
  CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            # "PASSWORD": "密码",
        }
    }
}

启动redis

去找f盘的redis
redis-server redis.windows.conf

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e3tRgjHi-1630375528308)(./代码截图/redis启动.png)]

https://www.cnblogs.com/yunqing/p/10605934.html

然后使用:剩下使用邮箱代替上面部分即可

QQ邮箱设置

stteings.py

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'  # 腾讯QQ邮箱 SMTP 服务器地址
EMAIL_PORT = 25  # SMTP服务的端口号
EMAIL_HOST_USER = '208633445@qq.com'  # 你的qq邮箱,邮件发送者的邮箱
EMAIL_HOST_PASSWORD = 'slbsatkpmlmqcbbe'  # 你申请的授权码(略)
EMAIL_USE_TLS = False  # 与SMTP服务器通信时,是否启用安全模式

调用:

from django.core.mail import send_mail

subject = '爱读书'  # 主题
from_email = settings.EMAIL_HOST_USER  # 发件人,在settings.py中已经配置
to_email = qqemail  # 邮件接收者列表
# 发送的消息
message = f'你本次的验证码:{random_code},有效时间为30秒'  # 发送普通的消息使用的时候message

send_mail(subject, message, from_email, [to_email],
          fail_silently=False, auth_user=None, auth_password=None,
          connection=None, html_message=None)

验证登录

  • 序列化器
    class LoginSerializer(serializers.Serializer):  # 对用户提交数据校验
      code = serializers.CharField(label="qq验证码", )
      qqemail = serializers.CharField(label="qq邮箱", validators=[qqemail_validator, ])
    
      def validate_code(self,value):
    
          if len(value) != 4:
              raise ValidationError('短信格式错误')
    
          if not value.isdecimal():
              raise ValidationError('短信格式错误')
    
          qqemail = self.initial_data.get('qqemail')
          coon = get_redis_connection()
          code = coon.get(qqemail)
    
          if not code:
              raise ValidationError('验证码过期')
    
          if value != code.decode('utf-8'):
              raise ValidationError('验证码错误')
          print(value)
          return value
    
  • POST处理
class LoginView(APIView):
    def post(self, request, *args, **kwargs):
        # 校验QQ号是否违法
        # 校验验证码
        # 1.无验证码
        # 2有验证码
        # 3.输入错误
        # 去数据库中获取用户信息(获取创建)
        # 将一些信息范湖小程序
        ser = LoginSerializer(data=request.data)
        print(request.data)
        print(ser.is_valid())
        # 成功
        if ser.is_valid():
            pass
        else:
            return Response({'status': False, 'message': '验证错误'})
        qqemail = ser.validated_data.get('qqemail')
        user_object, flag = models.UserInfo.objects.get_or_create(qqemail=qqemail)
        user_object.token = str(uuid.uuid4())
        user_object.save()
        return Response({'status': True, 'data': {'token': user_object.token, 'qqemail': qqemail}}, )

    def get(self, request):
        print(request.data)
        return Response({"status": 201})
  • 小程序发送请求
  wx.request({
   url: 'http://127.0.0.1:8000/login/',
   data: {qqemail: this.data.qqemail,code:this.data.code},
   method: 'POST',
   dataType:'json',
   success: function(result){
        console.log(result.data)
        //登录成功
        //将qq号放到全局的位置
        //1.去公共的app。js中获取globalData
       
        app.globalData.qqemail=result.data.data.qqemail
        console.log(app.globalData.qqemail)
        if (result.data.status){
          //跳转到上一级页面
          var pages=getCurrentPages();
          var prepage=pages[pages.length-2]
         
        /*wx.navigateTo({
          url: prepage,
        })*/
        wx.navigateBack({});
         }
        //登录失败
        else{
          wx.showToast({
            title: '登录失败',
            icon:"none"
          })
        } 
      
      },
   
 })
},
  • 全局变量
    首先在app.js中gloableData声明变量
    然后其他的页面调用:

var app=getApp()
app.gloableData.xxx

  • 返回上页面

     wx.navigateBack({});
             
    
  • 接口请求qq昵称头像

     var qq=this.data.qqemail
      var qqnum=(qq+'').replace('@qq.com',"")
      var url='http://q1.qlogo.cn/g?b=qq&nk=xx&s=100'.replace('xx',qqnum)
      this.setData({head:url})
      console.log(this.data.head)
    
  • 昵称(有乱码)

本地存储

  • 存储
    • wx.setStorageSync(‘UserInfo’,result);
  • 取值
    • var userinfo=wx.getStorageSync(‘UserInfo’);
  • 删除
    • wx.removeStorageSync(‘UserInfo’)

发布–子页面向向父页面传值

父页面

<view bindtap="getTopic">{{topicText}}</view>

 data: {
    topicText:"请选择话题",
    topicid:null
},
//修改子页面传过来的值
 pagesetData:function(res){
  this.setData({topicText:res.title,topicid:res.id})
},

子页面

 <view class='item' wx:for="{{topiclist}}" bindtap="choseTopic" data-xx="{{item}}">
  <text>{{item.title}} </text>
  <text>{{item.count}}</text>
</view>

data: {
  topiclist:[{id:1,title:'#吴亦凡太垃圾了',count:100},
    {id:2,title:'#金牌第二 ',count:100},
    {id:3,title:'#喜欢听歌',count:100},
    {id:4,title:'#网易云了',count:100}]
},

  choseTopic:function(e){
  var topicinfo=e.currentTarget.dataset.xx;
  //将值传递给上一个页面
  var pages=getCurrentPages();//获取当前页面
  var prevPage=pages[pages.length-2]//获取上一页面的对象
  prevPage.pagesetData(topicinfo)
  wx.navigateBack({}),
  console.log(topicinfo)
},

腾讯云的对象存储oss

SecretId: AKIDd5HCrGQt76oFQL0SeZEcjbDYcQxEExOa
SecretKey: wby5vUmnZ4IFvKSItCEzSfbFcjYWEfqj
APPID:1306812331

首先登陆腾讯云
然后选择对象存储
然后选择产看小程序sdk
然后在按照文档说明
使用的时候推荐方案一
通过后端回去秘钥返回

代码:

  • wx:
upload:function(){
  //方法1
  // var cos = new COS({
  //   SecretId: 'AKIDd5HCrGQt76oFQL0SeZEcjbDYcQxEExOa',
  //   SecretKey: 'wby5vUmnZ4IFvKSItCEzSfbFcjYWEfqj',
  // });

  //方法2 获取临时秘钥
  var cos = new COS({
    // 必选参数
    getAuthorization: function (options, callback) {
        // 服务端 JS 和 PHP 示例:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
        // 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
        // STS 详细文档指引看:https://cloud.tencent.com/document/product/436/14048
        wx.request({
            url: 'http://127.0.0.1:8000/credential/',
            data: {
                // 可从 options 取需要的参数
            },
            success: function (result) {
                var data = result.data;
                var credentials = data && data.credentials;
                if (!data || !credentials) return console.error('credentials invalid');
                callback({
                    TmpSecretId: credentials.tmpSecretId,
                    TmpSecretKey: credentials.tmpSecretKey,
                    XCosSecurityToken: credentials.sessionToken,
                    // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
                    StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
                    ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
                });
            }
        });
    }
  });
  console.log(this.data.piclist);
  for (var index in this.data.piclist){
    var filePath=this.data.piclist[index]//获取本地上传图片路径
    // 先选择文件,得到临时路径

    cos.postObject({
    Bucket: 'mini-1306812331',
    Region: 'ap-chengdu',
    Key:index+'x1.png',
    FilePath: filePath,
    onProgress: function (info) {
        console.log('进度条',JSON.stringify(info));

    }
}, function (err, data) {

    console.log(err || data);
});
  }

  

},
  • 后端
class Credential(APIView):


  def get(self,request,*args,**kwargs):
      from django.conf import settings
      config = {
          'url': 'https://sts.tencentcloudapi.com/',
          # 域名,非必须,默认为 sts.tencentcloudapi.com
          'domain': 'sts.tencentcloudapi.com',
          # 临时密钥有效时长,单位是秒
          'duration_seconds': 1800,
          'secret_id': 'AKIDd5HCrGQt76oFQL0SeZEcjbDYcQxEExOa',
          # 固定密钥
          'secret_key': 'wby5vUmnZ4IFvKSItCEzSfbFcjYWEfqj',
          # 换成你的 bucket
          'bucket': 'mini-1306812331',
          # 换成 bucket 所在地区
          'region': 'ap-chengdu',
          # 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径
          # 例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
          'allow_prefix': '*',
          # 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
          'allow_actions': [
              'name/cos:PostObject',
              --------相关权限-------------

          ],

      }
      sts=Sts(config)
      response=sts.get_credential()
      return Response(response)

发布问题

方式1.
打开图片进行本地预览
输入文字以及相应的信息
点击发布按钮

  • 将本地的图片上传到腾讯云对象存储中cos 并将cos中的地址返回。
  • 将cos中的url和文字等信息一起提交到后台
  • 可能拿不到cos中的图片

在发送请求的时候是异步的,不会阻塞

方式2.(推荐)
打开图片进行本地浏览
将本地图片上传到cos
输入文字,选择信息
发不完以后才可以点击按钮

进度条组件

这里显示上传图片的进度条为例

<progress percent="20" ></progress>
<view>进度:20%</view>
<progress percent="20" color="#dc1239"></progress>

修改data的局部数据

 data: {
    persent:20,
    piclist:[
      {id:1,title:'图片1',percent:20},
      {id:2,title:'图片2',percent:40},
      {id:3,title:'图片3',percent:70},
    ]
  },
  change:function(){
    /*方式1 数据多了就很慢
    var datalist=this.data.piclist
    datalist[0].percent=80
    this.setData({piclist:datalist})*/

    /*方式2 推荐*/
    var num=2 
    this.setData({['piclist[0].percent']:90,
    ['piclist[1].percent']:90,
    ['piclist['+num+'].percent']:90})//字符串拼接
  },

闭包

可以解决异步index问题,如进度条

api封装

新建文件夹config/api.js和page同级别

var indexUrl="http://127.0.0.1:8000"
module.exports={
getnews:indexUrl+"/getnews",
}
  • 引入

    var api=(’…/…/config/api.js’)

发布

小程序:


<!--编辑区-->
<textarea name="sd" id="" cols="30" rows="10" placeholder="请输入你的talk"></textarea>
<view class="tu">
<!--上传图片区-->
<view class="pic" wx:for="{{piclist}}">
  <image class="picm" src="{{item}}"></image>
  
  <view class="delete-btn" ><image  data-index="{{index}}" catchtap="deleteImg" src="../image/delete.png"></image></view>
  <progress class="progress" percent="{{imgs[index].percent}}"></progress>
</view>
<!--上传图片按钮-->
<image bindtap="upLoadImage" class="uppic" src="../image/uppicture.png"></image>
</view>

<!--标签-->
<view class="label">
<view class="label1" bindtap="getTopic"><image src="../image/place (2).png"></image> <view class="text">{{topicText}}</view></view>
<view class="label1" bindtap="getLocalPath"><image src="../image/place (1).png" ></image> <view class="text">{{sublocalpath}}</view></view>
</view>



<view class="line"></view>


<view class="fabu">
  <button bindtap="upload" class="but">发表</button>
</view>


<view class="bac">
  <view>每天开心一点点</view>
</view>

js逻辑

data

 topicText:"添加标签",
    localpath:"添加地点",
    sublocalpath:"添加地点",//截取后的位置信息
    piclist:[],//上传下载使用
    urls:[],//图片地址

    imgs:[],//渲染使用
    progress:0,

    qqemail:null,
    qqname:null,
    head:'../image/head.jpg',
    UserInfo:'',
   
    body:null,

获取话题

getTopic:function(){
    wx.navigateTo({
      url: '/pages/topic/topic',
    })
  },
pagesetData:function(res){
    this.setData({topicText:res.title,topicid:res.id})
},

获取定位

getLocalPath:function(){
    console.log("1")
    var that=this
    wx.chooseLocation({
      success:function(res){
      console.log(res.address)
      that.setData({localpath:res.address,sublocalpath:res.address.substring(0,4)+"...",localpath:res.address})
      }
    })
  },

删除图片

 //删除图片
  deleteImg: function (e) {
    //删除本地
    var that=this
    var imgs = that.data.piclist;
    var index = e.currentTarget.dataset.index;
    imgs.splice(index, 1);
    that.setData({
     piclist: imgs
    });
    //删除对象存储
    cos.deleteObject({
      Bucket: 'mini-1306812331',
      Region: 'ap-chengdu',
      Key: that.data.imgs[index].key,
      
    }, function (err, data) {
      console.log(err || data); 
    });
    var url = cos.getObjectUrl({
      Bucket: 'mini-1306812331',
      Region: 'ap-chengdu',
      Key: that.data.imgs[index].key,
      
   });
   console.log('url=',url)
   },

获取日期

 onLoad: function (options) {
    var myDate = new Date();
    var riqi=myDate.toLocaleDateString();  //获取日期
    console.log(riqi)
  },

选择本地图片并且上传到oss

 upLoadImage:function(){
    
    var that=this
    var imgs = this.data.imgs;
   
    wx.chooseImage({
      count:9,//最多选择9张图片
      sizeType:['original', 'compressed'],//原图;压缩图
      sourceType:['album', 'camera'],//选择相册和相机

      success:function(res){//成功后
        var oldlength=that.data.piclist.length;
        // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
        let tempFilePaths = res.tempFilePaths;
        let totalcount=res.tempFilePaths.length+oldlength;//总照片数
        if(totalcount>9){
          wx.showToast({
            title: '图片最多选择9张',
            icon:'none'
          });
          return
        };

        var piclist=that.data.piclist.concat(res.tempFilePaths);//concat将两个列表合并,但是不改变原来列表的值,他///们重新复制给心得列表
        /**本地预览 */
        that.setData({piclist:piclist})
        //方法2 获取临时秘钥
   
    console.log(that.data.piclist);
    for (let index in res.tempFilePaths){

      var filePath=res.tempFilePaths[index]//http://tmp/t4TusS4AKmhG70b46dc9e64ad9aa477e1fff6cf646b7.jpg
      var filePathSplit=filePath.split('.');
      console.log("xxxxxxx",filePathSplit)//http://tmp/t4TusS4AKmhG70b46dc9e64ad9aa477e1fff6cf646b7
      var ext=filePathSplit[filePathSplit.length-1]
      console.log("ext=",ext)//jpg
      //创建随机字符串
      let randomString=Math.random().toString(36).slice(-8)+String(new Date().getDate())
      console.log("随机字符串",randomString)
      var filekey=randomString+"."+ext;//自己组和的xxx.jpg

      //将新的名字复制给piclist[key]=filekey
      that.setData({
        ['imgs['+oldlength+parseInt(index)+'].key']:filekey})

      cos.postObject({
      Bucket: 'mini-1306812331',
      Region: 'ap-chengdu',
      Key:filekey,
      FilePath: filePath,
      onProgress: function (info) {
        that.setData({
          ['imgs['+oldlength+parseInt(index)+'].percent']:info.percent*100
        })
        //如果进度条满了就可以删除
        if(imgs[index].percent==100){
          that.setData({
            ['imgs['+oldlength+parseInt(index)+'].delpic']:info.percent*100
          })
        }
      }
  }, function (err, data) {

      console.log(err || data);
  });
    }
  
  
      },
     
    });
  },
   

细节处理
css:
使用 overflow: scroll;
可以让图片隐藏滑动,适用于很多的图片

api设计

1.数据库设计

  • 话题
class Topic(models.Model):
      topic=models.CharField(verbose_name="话题",max_length=32)
      hot=models.IntegerField(verbose_name="热度")
  • 动态

class News(models.Model):
    """
    动态
    """
    cover = models.CharField(verbose_name='封面', max_length=128)
    content = models.CharField(verbose_name='内容', max_length=255)
    topic = models.ForeignKey(verbose_name='话题', to='Topic',on_delete=models.CASCADE, null=True, blank=True)
    address = models.CharField(verbose_name='位置', max_length=128, null=True, blank=True)

    user = models.ForeignKey(verbose_name='发布者', to='UserInfo', related_name='news',on_delete=models.CASCADE)

    favor_count = models.PositiveIntegerField(verbose_name='赞数', default=0)
    # favor = models.ManyToManyField(verbose_name='点赞记录', to='UserInfo', related_name="news_favor")

    viewer_count = models.PositiveIntegerField(verbose_name='浏览数', default=0)
    # viewer = models.ManyToManyField(verbose_name='浏览器记录', to='UserInfo', related_name='news_viewer')

    comment_count = models.PositiveIntegerField(verbose_name='评论数', default=0)

    create_date = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
  • 动态详细,外键为动态
class NewsDetail(models.Model):
    """
    动态详细
    """
    key = models.CharField(verbose_name='腾讯对象存储中的文件名', max_length=128, help_text="用于以后在腾讯对象存储中删除")
    cos_path = models.CharField(verbose_name='腾讯对象存储中图片路径', max_length=128)
    news = models.ForeignKey(verbose_name='动态', to='News',on_delete=models.CASCADE)

    def __str__(self):
        return str([self.cos_path,self.key])

序列化
这里涉及嵌套的反序列化,用于create
使用外键的序列化,注意序列化内部使用序列化


class CreateNewsTopicModelSerializer(serializers.Serializer):
    key = serializers.CharField()
    cos_path = serializers.CharField()


class CreateNewsModelSerializer(serializers.ModelSerializer):
    imageList = CreateNewsTopicModelSerializer(many=True)

    class Meta:
        model = models.News
        exclude = ['user', 'viewer_count', 'comment_count']

    def create(self, validated_data):
        image_list = validated_data.pop('imageList')
        news_object = models.News.objects.create(**validated_data)

        data_list = models.NewsDetail.objects.bulk_create(
            [models.NewsDetail(**info, news=news_object) for info in image_list]
        )
        news_object.imageList = data_list

        if news_object.topic:
            news_object.topic.hot += 1
            news_object.save()

        return news_object


class NewsDetailSer(serializers.Serializer):
    key = serializers.CharField()
    cos_path = serializers.CharField()

##获取news
class NewsSer(serializers.Serializer):
    cover =serializers.CharField()
    content =serializers.CharField()
    topic =TopicSer()
    address = serializers.CharField()
    user =serializers.StringRelatedField(read_only=True)
    favor_count =serializers.IntegerField()
    # favor = models.ManyToManyField(verbose_name='点赞记录', to='UserInfo', related_name="news_favor")

    viewer_count = serializers.IntegerField()
    # viewer = models.ManyToManyField(verbose_name='浏览器记录', to='UserInfo', related_name='news_viewer')

    comment_count = serializers.IntegerField()
    create_date = serializers.DateTimeField()
    newsdetail_set=serializers.StringRelatedField(read_only=True,many=True)

外键序列化 (重点)

在序列化字段的是时候使用:

  • 方式1
    PrimaryKeyRelatedField()
    这里参数:only_read=True or queryset=…OBJ.all()
  • 方式2
    在模型类里面使用
 __str__() 
序列化字段时:
StringRelatedFiled()
  • 方式3
    在字段里使用序列化类
    先定义一个序列化类,然后在序列化字段时使用
在一方中序列化另外有外键的一方(灰常好使,不要怕错)
使用小写类名_set=serlizers.PrimaryKeyRealetd(only=True,many=True)
  • views的设计
class NewsView(CreateAPIView,ListAPIView):
    """ 创建动态的API """
    serializer_class = CreateNewsModelSerializer
    queryset = models.News.objects.all()
    def perform_create(self, serializer):
        new_object=serializer.save(user_id=1)
        return new_object

from .ser import NewsSer,NewsDetailSer
class GetNews(APIView):
    def get(self, request, *args, **kwargs):
        queryset = models.News.objects.all().order_by("-id")[0:10]
        ser = NewsSer(instance=queryset, many=True)
        return Response(ser.data)

class GetNewsDetail(APIView):
    def get(self, request, *args, **kwargs):
        queryset = models.NewsDetail.objects.all()
        ser = NewsDetailSer(instance=queryset, many=True)
        return Response(ser.data)

class GetNewsDetailOnly(APIView):
    def get(self, request,pk):
        queryset = models.NewsDetail.objects.filter(news_id=pk)
        ser = NewsDetailSer(instance=queryset, many=True)
        return Response(ser.data)

使用脚本对数据库进行初始化

import os
import sys
import django

base_dir=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_dir)

os.environ.setdefault("DJANGO_SETTINGS_MODULE","template.settings")
django.setup()

#====================数据库初始化脚本======================
from app03 import models

for i in range(1,37):
    models.Topic.objects.create(
        topic="今天很热",hot=100
    )
    models.News.objects.create(
           cover="https://mini-1306812331.cos.ap-chengdu.myqcloud.com/lme85byh23.jpg",
           content ="第{}只羊".format(i),
           topic_id =i,
           address ="云南",
           user_id =1,
        )
    models.NewsDetail.objects.create(
        key= 'lme85byh23.jpg',
        cos_path='https://mini-1306812331.cos.ap-chengdu.myqcloud.com/lme85byh23.jpg',
        news_id=i
    )
    models.NewsDetail.objects.create(
        key='lme85byh23.jpg',
        cos_path='https://mini-1306812331.cos.ap-chengdu.myqcloud.com/lme85byh23.jpg',
        news_id=i
    )
    models.NewsDetail.objects.create(
        key='jrpzjj8w16.jpg',
        cos_path='https://mini-1306812331.cos.ap-chengdu.myqcloud.com/jrpzjj8w16.jpg ',
        news_id=i
    )

箭头函数

可以不用将this转换成that

上拉刷新–下拉刷新

  • js
/**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
    var that=this
    wx.request({
      //获取新闻列表
      url:'http://127.0.0.1:8000/get1topic/',
      data:{
        maxid:that.data.maxid
      },
      dataType:"json",
      responseType:'text',
      method: 'GET',
      success: (result) => {console.log(result.data)
       if(result.data.length){
         wx.showToast({
           title: '已经是最新数据',
          
         })
        
       }
       wx.stopPullDownRefresh({
         success: (res) => {return},
         
       })
      
         var newdata=result.data.reverse()//将数据反转
         that.setData({data:newdata.concat(that.data.data),maxid:newdata[0].id})
     
      },
    })
  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    var that=this
    wx.request({
      //获取新闻列表
      url:'http://127.0.0.1:8000/get1topic/',
      data:{
        minid:that.data.minid
      },
      dataType:"json",
      responseType:'text',
      method: 'GET',
      success: (result) => {console.log(result.data)
       if(result){
      that.setData({data:that.data.data.concat(result.data),minid:result.data[result.data.length-1].id})
       }
      },
    })
  },

  • json
{
  "usingComponents": {},
  "enablePullDownRefresh": true
}
  • api
class GetNews(APIView):
    def get(self, request, *args, **kwargs):
        minid=request.query_params.get('minid')
        maxid = request.query_params.get('maxid')
        if not minid:
            queryset = models.News.objects.all().order_by("-id")[0:10]
        elif maxid:
            queryset = models.News.objects.filter(id__gt=maxid).order_by("id")[0:10]
        else:
            queryset = models.News.objects.filter(id__lt=minid).order_by("-id")[0:10]
        ser = NewsSer(instance=queryset, many=True)
        return Response(ser.data)

  • api优化
    可以使用分页器和filterbackend来共同完成

注意

数据库删除问题:
删除时必须将表django_migrations中的相关文件删除
这东西浪费了我很久时间!

轮播图组件

  • js
// components/theSwiper.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    imgUrls: Array,
  },

  /**
   * 组件的初始数据
   */
  data: {
    currentIndex: 0
  },
  /**
   * 组件的方法列表
   */
  methods: {
    swiperChange(e) {
      this.setData({
        currentIndex: e.detail.current
      });
    }
  }
});
/*

<view class="dots-box own-class">
  <view class="dots {{currentIndex == index ? 'bg-333' : ''}}" wx: for="{{ imgUrls }}" wx:key="{{ index }}"></view>
</view >
*/
```json
json

{
  "component": true,
  "usingComponents": {}
}

wxml
```wxml
<swiper indicator-dots="false" 
        autoplay="{{true}}" 
        interval="5000" 
        indicator-dots="{{false}}" 
        indicator-color='#8a8a8a' 
        indicator-active-color='#333' 
        circular="true" 
        class="swiper-block" 
        bindchange="swiperChange" 
        previous-margin="100rpx" 
        next-margin="100rpx" 
        current="{{0}}">
  <block wx:for="{{imgUrls}}" wx:index="{{index}}" wx:key="{{index}}">
    <swiper-item class="swiper-item ">
      <image mode="aspectFill" src="{{item}}" class="slide-image {{currentIndex == index ? 'active' : 'common'}}" />
    </swiper-item>
  </block>
</swiper>

  • wxss
page{
  background-color: #fff;
}
.swiper-block {
  background: #fff;
  height: 500rpx;
  width: 100%;
}

.swiper-item{
  display: flex;
  flex-direction: column;
  justify-content: start;
  align-items: flex-start;
  overflow: unset;
  width: 550rpx;
  height: 450rpx;
  padding-top: 70rpx;
  padding-bottom: 20rpx;
  box-sizing: border-box;
}

.slide-image{
  height: 300rpx;
  width: 450rpx;
  border-radius: 10rpx;
  margin: 0rpx 50rpx ;
  z-index: 1;
  box-shadow: 10rpx 5px 40rpx rgba(0, 0, 0,0.5);
}
.active{
  transform: scale(1.3);
  transition: all .5s ease-in 0s;
  z-index: 20;
  opacity: 1;
}
.common{
  transform: scale(1);
  transition: all .5s ease-in 0s;
  z-index: 0;
  opacity: 0.4;
}

.dots-box{
  display: flex;
  justify-content: center;
  align-items: center;
}

.dots{
  width: 30rpx;
  height: 6rpx;
  margin: 0 4rpx;
  background-color: #aaa;
  margin-top: -80rpx;
}
.bg-333{
  background-color: #333;
}

----------------如何使用?------------------------

使用界面的 wxml 添加

json
这里组件地址写自己放组件的地址就行

{
  "usingComponents": {
    "custom-swiper": "../../components/customSwiper/customSwiper"
  },
}

js中的data添加数据:

  carouselImgUrls:[
      "https://wx1.sinaimg.cn/mw690/006cV2kkly1g90322akslj30on1hcjvf.jpg",
      "https://wx2.sinaimg.cn/mw690/006cV2kkly1g9032310y9j30on1hcdkw.jpg",
      "https://wx3.sinaimg.cn/mw690/006cV2kkly1g90323z18oj30on1hc77z.jpg",
      "https://wx1.sinaimg.cn/mw690/006cV2kkly1g90324d2mrj30on1hcwic.jpg",
      "https://wx3.sinaimg.cn/mw690/006cV2kkly1g903258itpj30on1hctby.jpg"
    ],

将对象转换成字典

modle_to_dict()

评论功能

  • 数据库设计
class  CommentRecored(models.Model):
    news=models.ForeignKey(verbose_name="动态",to='NewsDetail',on_delete=models.DO_NOTHING)
    content=models.CharField(verbose_name='评论内容',max_length=255)
    user=models.ForeignKey(verbose_name='评论者',to='UserInfo',on_delete=models.DO_NOTHING)
    create_date=models.DateTimeField(verbose_name='评论时间',auto_now_add=True)

    reply=models.ForeignKey(verbose_name='回复',to='self',null=True,blank=True,related_name='replys',on_delete=models.SET_NULL)
    depth=models.PositiveIntegerField(verbose_name='评论层级数',default=1)
    root=models.ForeignKey(verbose_name='跟评论',to='self',null=True,blank=True,related_name='roots',on_delete=models.SET_NULL)

    favor_count=models.PositiveIntegerField(verbose_name='赞数',default=0)

里面不是递归,而是自相连
使用自相连的时候需要注意related——name需要填充

  • 序列化
    • 获取相关新闻及其评论信息
#获取news
class NewsSer(serializers.Serializer):
    id=serializers.IntegerField()
    cover =serializers.CharField()
    content =serializers.CharField()
    topic =TopicSer()
    address = serializers.CharField()
    user =serializers.StringRelatedField(read_only=True)
    favor_count =serializers.IntegerField()
    # favor = models.ManyToManyField(verbose_name='点赞记录', to='UserInfo', related_name="news_favor")

    viewer_count = serializers.IntegerField()
    # viewer = models.ManyToManyField(verbose_name='浏览器记录', to='UserInfo', related_name='news_viewer')

    comment_count = serializers.IntegerField()
    create_date = serializers.DateTimeField(format="%Y-%m-%d")
    newsdetail_set=serializers.StringRelatedField(read_only=True,many=True)

    comment=serializers.SerializerMethodField()

    def get_comment(self,obj):
        #一级评论
        first_comment=models.CommentRecored.objects.filter(news_id=obj.id,depth=1).order_by('id')[0:10].values(
            'id',
            'content',
            'user',
            'create_date',
            'favor_count',
            'depth'

        )
        first_comment_id=[item['id'] for item in first_comment]
        print(first_comment_id)
        #二级评论
        from django.db.models import Max #获取二级评论最新的一条
        #使用一级id分组,查询最新的二级评论的id,即获取每条一级评论下的最新一条二级评论
        result= models.CommentRecored.objects.filter(depth=2,reply_id__in=first_comment_id).values('id').annotate(max_id=Max('id'))
        second_id=[item['max_id'] for item in result]
        print(second_id)
        second_comment = models.CommentRecored.objects.filter(id__in=second_id).values(
            'id',
            'content',
            'user__qqemail',
            'create_date',
            'reply_id',
            'favor_count',
            'depth'

        )
        print(second_comment)
        ##合并一二级评论在一个关键字里
        #使用字典
        first_dict={}
        for item in first_comment:
            item['create_date']=item['create_date'].strftime('%Y-%m-%d')#2010-x-xx格式的日期
            first_dict[item['id']]=item
        for node in second_comment:
            node['create_date'] = node['create_date'].strftime('%Y-%m-%d') # 2010-x-xx格式的日期
            first_dict[node['reply_id']]['child']=[node,]
        return  list(first_dict.values())
  • 获取回复信息
  
class getcomment(serializers.Serializer):
    id=serializers.IntegerField()
    content=serializers.CharField()
    user__qqemail=serializers.CharField(source='user.qqemail')
    create_date=serializers.DateTimeField(format="%Y-%m-%d")
    reply_id=serializers.IntegerField()
    favor_count=serializers.IntegerField()
    depth=serializers.IntegerField()
  • 创建回复信息
class createfirstcomment(serializers.ModelSerializer):
    class Meta:
        model = models.CommentRecored
        fields="__all__"
  • views

from .ser import NewsSer,NewsDetailSer,getcomment
class GetNews(APIView):
    def get(self, request, *args, **kwargs):
        minid=request.query_params.get('minid')
        maxid = request.query_params.get('maxid')
        newid=request.query_params.get('newid')
        if  minid:
            queryset = models.News.objects.filter(id__lt=minid).order_by("-id")[0:10]
        elif maxid:
            queryset = models.News.objects.filter(id__gt=maxid).order_by("id")[0:10]

        elif newid:
            queryset = models.News.objects.filter(id=newid)
            vc=queryset.values_list('viewer_count')[0][0]
            queryset.update(viewer_count=vc+1)

        else:
            queryset = models.News.objects.all().order_by("-id")[0:10]
        ser = NewsSer(instance=queryset, many=True)
        return Response(ser.data)

class GetNewsDetail(APIView):
    def get(self, request, *args, **kwargs):
        queryset = models.NewsDetail.objects.all()
        ser = NewsDetailSer(instance=queryset, many=True)
        return Response(ser.data)

class GetComment(APIView):
    def get(self,requset,*args,**kwargs):
        itid=requset.GET.get('itemid')
        obj=models.CommentRecored.objects.filter(reply_id=itid)
        ser=getcomment(instance=obj,many=True)

        return Response(ser.data)
from .ser import createfirstcomment
class CreateComment(CreateAPIView):
    serializer_class = createfirstcomment

  • 小程序端

  • html
<!--pages/newsdetail/newsdetail.wxml-->

<custom-swiper wx:if="{{carouselImgUrls.length}}" imgUrls="{{carouselImgUrls}}" />

<view class="user">
  <image src="../image/fabubac.jpg"></image>
  <text>多啦的碑文</text>
</view>

<view> {{data.content}}#{{data.topic.topic}}</view>
<view>浏览量:{{data.viewer_count}}</view>

<!--虚线-->
<view class="com">
  <view class="line"></view>
  <text>评论</text>
  <view class="line"></view>
</view>

<!--评论-->
<view class="pinglun">
  <view wx:for="{{data.comment}}">
    <view class="first">
      <view class="head">
        <image src="../image/fabubac.jpg"></image>
      </view>
      <view class="sec">
        <view style="font-weight:600">多啦的碑文</view>
        <view class="ba">{{item.create_date}}<view class="back" bindtap="huifu" data-uer="多啦的碑文"  data-replyid="{{item.id}}">回复</view></view> 
      </view>
      <view class="dianzan">
        <image src="../image/dianzan.png"></image>
        <text>{{item.favor_count}}</text>
      </view>
    </view>
    <view class="content">
      <view class="te">{{item.content}}<view class="huifu" bindtap="hui" data-itemid="{{item.id}}" data-idx="{{index}}">更多评论 ></view>
        <view wx:for="{{item.child}}" wx:for-item="idxs">
          <view class="first">
            <view class="head">
              <image src="../image/fabubac.jpg"></image>
            </view>
            <view class="sec">
              <view>多啦的碑文</view>
              <view>{{idxs.create_date}}</view>
            </view>
            <view class="dianzan">
              <image src="../image/dianzan.png"></image>
              <text>{{idxs.favor_count}}</text>
            </view>
          </view>
          <view class="te">{{idxs.content}}</view>
        </view>
      </view>
    </view>
  </view>
</view>

<view class="fpl">
  <textarea placeholder="{{tolk}}" class="texa" bindinput="textcont"></textarea>
  <button bindtap="ok" data-data="{{data}}">确认</button>
</view>
  • 样式css
/* pages/newsdetail/newsdetail.wxss */
.user{
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 40%;
}
  image{
    float: left;
    margin-left: 10rpx;
    width: 100rpx;
    height: 100rpx;
    border-radius: 50%;
  }
.com{
  margin-top: 20rpx;
  display: flex;
  justify-content: space-around;
  align-items: center;
}
.line{
  width: 43%;
  border-bottom: 0.5rpx dotted gray;
}
.first{
width: 100%;
height: 80rpx;

margin-top: 25rpx;

}
.head{
  width: 80rpx;
  height: 80rpx;
  border-radius: 50% ;
  float: left;
  
}
.head image{
width: 100%;
height: 100%;
}
.sec{
float: left;
margin-left: 15rpx;
}
.dianzan{
 float: right;
  width: 15%;
  height: 80rpx;
 margin-right: 15rpx;
  
}
.dianzan image{

 margin-top: 10rpx;
width: 50%;
height: 65%;  
}
.dianzan text{
  line-height: 80rpx;
 }
 .content{
   float: none;
 
   width: 100%;
   margin-top: 5rpx;
 }

 .te{
   margin-top: 10rpx;
   background-color: rgb(236, 236, 236);
   white-space:pre-wrap;
   margin-left: 12%;
 }
 .fpl{
  width: 100%;
  height: 100rpx;
  position: fixed;
  bottom: 0rpx;
 border: 1rpx sandybrown;
 background-color: rgb(224, 224, 224);
  display: flex;
  justify-content: space-between;
  flex-direction: row;

 }
.fpl textarea{
  white-space:pre-wrap ;
  width: 70%;
  background-color: #f5f6f8;
  height: 80%;
  margin-left: 20rpx;
  border-radius: 5rpx;
  margin-top: 10rpx;
}
.fpl button{
margin-top: 10rpx;
 line-height: 80rpx;
  width:20%;
  height: 80%;
  float:right;
  right: 20rpx;
  background-color: rgb(235, 192, 144);
  border-radius: 8rpx;
}
.pinglun{
 
  margin-bottom:200rpx;
}
.back{
  float: right;
  font: weight 500;
  font-size: 30rpx;
}

  • js
// pages/newsdetail/newsdetail.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    carouselImgUrls:null,
    data:[],
   
    head:'../image/head.jpg',
    UserInfo:'',
    ishuifu:true,
    isfu:false,
    option:null,

    tolk:"留下点你来过的痕迹吧",

    /*以下是发送的评论*/ 
    textaea:null,
    reply:null,
    depth:1,
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
   console.log("optoions",options)
   this.setData({option:options})
    var that=this
    wx.request({
      //获取新闻列表
      url:'http://127.0.0.1:8000/get1topic/',
      dataType:"json",
      data:{
        newid:options.newsid
      },
      responseType:'text',
      method: 'GET',
      success: (result) => {console.log("result1data=",result.data)
       
      that.setData({data:result.data[0],carouselImgUrls:result.data[0].newsdetail_set})
     
      console.log("res====>",result.data[0].newsdetail_set)
      },
     
    })
 
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },
  hui:function(e){

  console.log("data---",this.data.data)
  var that=this
  //console.log(this.data.data.comment[1].child[0])
  var itemid=e.currentTarget.dataset.itemid
  var idx=e.currentTarget.dataset.idx
  console.log("idex=",idx)
  console.log("itemid=",itemid)
  wx.request({
    url: 'http://127.0.0.1:8000/getcom/?itemid='+itemid,
    dataType:'json',
    method: 'GET',
    responseType: 'text',
    timeout: 0,
    success: (result) => {console.log('result=',result)
    that.setData({
     ['data.comment['+idx+'].child']:result.data,isfu:true
    })
    console.log("childdata=",this.data.data)
    },
    
  })
 
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {


  },
/*评论内容*/ 
textcont:function(e){
console.log(e.detail.value)
this.setData({textaea:e.detail.value})
},
ok:function(){
  var that=this
  console.log("id=",this.data.data.id)
  console.log(that.data.reply)
  wx.request({
    //获取新闻列表
    url:'http://127.0.0.1:8000/upcomment/',
    dataType:"json",
    data:{
    
      "news":that.data.data.id,
      "content":that.data.textaea,
      "user":1,
      "depth":that.data.depth,
      "reply":that.data.reply
    },
    responseType:'text',
    method: 'POST',
    success: (result) => {
      console.log('ok')
      that.onLoad(that.data.option)
    },
  })
},
/**回复 */
huifu:function(e){
  var replyid=e.currentTarget.dataset.replyid
 console.log(replyid)
this.setData({tolk:"回复:多啦的碑文",depth:2,reply:replyid})

},
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

用户认证

使用请求头将token传递过去

header{
Authorization
}

然后get请求里使用

token=request.META.get(‘HTTP_AUTHORIZATION’,None)

None所在的参数是如果没有取到token就为空,或者可以不用设为nONE,设置为其他的字符

自定义认证组件

在app下新建 author.py

然后

from rest_framework.authentication import BaseAuthentication
from .models import UserInfo
import models
class GeneralAuthentication(BaseAuthentication):
    """
    通用认证,如果成功返回数据,不成功不处理,交给下一组件处理
    """
    def authenticate(self, request):
        token=request.META.get('HTTP_AUTHORIZATION',None)
        if not token:
            return None
        user_object=models.UserInfo.objects.filter(token=token).first()
        if not user_object:
            return None
        #成功
        return (user_object,token)

在seetings.py中设置

REST_FRAMEWORK={
    "UNAUTHENTICATED_USER":None,
    "UNAUTHENTICATED_TOKEN":None
}

然后在需要认证的接口视图中添加

authentication_classes = [GeneralAuthentication,]

使用
在请求方式里面
request.user
request.token

  • 设置成全局的认证 在settings.py中添加默认的认证类,

    REST_FRAMEWORK={
    “DEFAULT_AUTHENTICATION_CLASS”:[‘app03.author.GeneralAuthentication’,],
    “UNAUTHENTICATED_USER”:None,
    “UNAUTHENTICATED_TOKEN”:None
    }

  • 用户的认证–>登录认证

class UserAuthentication(BaseAuthentication):
    """
    用户认证,如果成功返回数据,不成功抛异常
    """
    def authenticate(self, request):
        token=request.META.get('HTTP_AUTHORIZATION',None)
        if not token:
            raise exceptions.AuthenticationFailed()#返回403
        user_object=models.UserInfo.objects.filter(token=token).first()
        if not user_object:
            raise exceptions.AuthenticationFailed()#返回403
        #成功
        return (user_object,token)

使用

  • 判断是post
  • 然后在使用该认证类
    在视图函数中
  if self.request.method=='POST':
            return [UserAuthentication(),]
        return [GeneralAuthentication(),]
          

自定义tabbar

  • 步骤1
    导入官方文档里的自定义tabbar案例,导入到compononts/tabbar中
    • js
var app=getApp()
Component({
  properties:{
    selected: {
      type:Number,
      value:0
    }
  },
  data: {
   
    color: "#7A7E83",
    selectedColor: "#3cc51f",
    list: [
     {
      pagePath: "/pages/news/news",
      //iconPath: "/image/icon_component.png",
      //selectedIconPath: "/image/icon_component_HL.png",
      text: "首页"
    }, {
     
      text: "发布"
    }, {
      pagePath: "/pages/main/main",
      //iconPath: "/image/icon_component.png",
      //selectedIconPath: "/image/icon_component_HL.png",
      text: "我的"
    },]
  },
  attached() {
  },
  methods: {
    switchTab(e) {
      const data = e.currentTarget.dataset
      const url = data.path
      if(url){
        wx.switchTab({url})
      }
      else{
      if(app.globalData.UserInfo){
        wx.switchTab({
          url: '/pages/publish/publish',
        })}
        else{
          wx.navigateTo({
            url: '/pages/home/home',
          })
         
        }
      }

    }
  }
})

需要注意 wx.switchTab()跳转的是tababr页面
wx.navigateTo()是非tabbar页面

  • wsml
<cover-view class="tab-bar">
  <cover-view class="tab-bar-border"></cover-view>
  <cover-view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
    <block wx:if="{{item.text=='发布'}}" >
      
    <cover-view class="pub" style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</cover-view>
  </block>
  <block wx:else>
    <cover-image src="{{selected === index ? item.selectedIconPath : item.iconPath}}"></cover-image>
    <cover-view style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</cover-view>
  </block>


  </cover-view>
</cover-view>
  • json

    {
    “component”: true
    }

  • css

.tab-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 48px;
  background: white;
  display: flex;
  padding-bottom: env(safe-area-inset-bottom);
}

.tab-bar-border {
  background-color: rgba(0, 0, 0, 0.33);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 1px;
  transform: scaleY(0.5);
}

.tab-bar-item {
  flex: 1;
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.tab-bar-item cover-image {
  width: 27px;
  height: 27px;
}

.tab-bar-item cover-view {
  font-size: 10px;
}

.pub{
  background-color: #d39a32;
  height: 80rpx;
  width: 80rpx;
  border-radius: 50%;

  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
  • 第2步骤
    导入使用

  • json

"usingComponents": {
    "tabbar":"/components/tabbar/tabbar"
  },
  • wxml
<tabbar selected="{{0}}"></tabbar>

注意 selested里面的值是锁引值,数据是第几个,点击后会变色

在序列化类里获取request

xx=serlizers.serlizerMtthod()
def get_xx(self):
request=self.context['request']

支付

1.沙箱环境
微信里没有
2.微信小程序支付
2.1微信支付平台

  • 个人
  • 企业
    2.2商户平台(企业)

暂时跳过

celery

处理任务的的python模块

  • 场景1:
    对于耗时的任务,将任务添加到broker(队列中),然后立即给用户一个任务id,当任务添加到broker之后,由worker去broker获取并处理任务
    任务完成后,再将结果放到backend中
    用户想要检查结果,提供任务id,我们可以去backen中去帮他查找。

  • 场景2:
    定时任务:定时发布,定时拍卖

celery是一个基于python开发的模块,可以对任务进行分发和处理

  • 安装(注意版本的区别)
    • pip3 install celery

    • 安装broker需要redis(已经安装)或者 rabbitMQ

    • pip3 install redis/pika

    • windows 需要另外安装

使用,参考网上教程

django-celery

为了使用jango和celery结合起来,使用jango-celery模块

  • 安装
  • 在seetings。py中配置

https证书申请

  • 阿里云 免费个人 ssl 下载

项目部署

找一台云服务器 安装nginx

yum install nginx -y

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值