分类 编程语言 下的文章

Query

查询内容

  1. 模型对象。指定查找这个模型中所有的对象。
  2. 模型中的属性。可以指定只查找某个模型的其中几个属性。

    user = session.query(User).first()
    username = session.query(User.username).first()

常用的filter操作符

  1. equals:

    user = session.query(User).filter(User.name == "sunxiaoning").first()
  2. not equals:

    query.filter(User.username != 'sunxiaoning').all()
  3. like:

    query.filter(User.username.like('%ning%'))
  4. in:

    query.filter(User.username.in_(['sun','xiao','ning']))
    
    query.filter(User.username.in_(
        session.query(User.username).filter(User.username.like('%sun%'))
    ))
  5. not in:

    query.filter(~User.username.in_(['sun','xiao','ning']))
  6. is null:

    query.filter(User.username==None)
    # OR
    query.filter(User.username.is_(None))
  7. is not null:

    query.filter(User.username != None)
    # OR
    query.filter(User.username.isnot(None))
  8. and:

    from sqlalchemy import and_
    query.filter(and_(User.username=='sun', User.age<18))
    # 或者是传递多个参数
    query.filter(User.username=='sun', User.age<18)
    # 或者是通过多次filter操作
    query.filter(User.username=='sun').filter(User.age<18)
  9. or:

    from sqlalchemy import or_  
    query.filter(or_(User.username=='sun', User.age<18))
  10. MATCH:

    query.filter(User.username.match('sun'))
SQLAlchemy中filter()和filter_by()的区别:
1、filter引用列名时,使用“类名.属性名”的方式,比较使用两个等号“==”
2、filter_by引用列名时,使用“属性名”,比较使用一个等号“=”
3、在使用多条件匹配的时候,filter需要借助sqlalchemy里的and_ ; 而filter_by不需要,直接把多个匹配条件写在一起
4、在使用多条件匹配时,用到>=、>、<=、<的情况,貌似不能使用filter_by。可能是姿势不对

返回列表(List)和单项(Scalar)

  • all()返回一个列表。
  • first()返回至多一个结果,而且以单项形式,而不是只有一个元素的tuple形式返回这个结果。
  • one()返回且仅返回一个查询结果。当结果的数量不足一个或者多于一个时会报错。一般使用first()。
  • one_or_none():从名称可以看出,当结果数量为0时返回None, 多于1个时报错。
  • scalar()和one()类似,但是返回单项而不是tuple。

排序:

  1. order_by:可以指定根据这个表中的某个字段进行排序,如果在前面加了一个-,代表的是降序排序。
  2. 在模型定义的时候指定默认排序:有些时候,不想每次在查询的时候都指定排序的方式,可以在定义模型的时候就指定排序的方式。有以下两种方式:

    • relationship的order_by参数:在指定relationship的时候,传递order_by参数来指定排序的字段。
    • 在模型定义中,添加以下代码:

      __mapper_args__ = {
       "order_by": _id
       }
  3. 正序排序与倒序排序:默认是使用正序排序。如果需要使用倒序排序,那么可以使用这个字段的desc()方法,或者是在排序的时候使用这个字段的字符串名字,然后在前面加一个负号。

计数

Query定义了一个很方便的计数函数count()

limit、offset和切片操作:

  1. limit:可以限制每次查询的时候只查询几条数据。
  2. offset:可以限制查找数据的时候过滤掉前面多少条。
  3. 切片:可以对Query对象使用切片操作,来获取想要的数据。可以使用slice(start,stop)方法来做切片操作。也可以使用[start:stop]的方式来进行切片操作。一般在实际开发中,中括号的形式是用得比较多的。希望大家一定要掌握。示例代码如下:

    users = session.query(User).order_by(User._id.desc())[0:10]

    聚合函数

    • func.count:统计行的数量。
    • func.avg:求平均值。
    • func.max:求最大值。
    • func.min:求最小值。
    • func.sum:求和。
      func上,其实没有任何聚合函数。但是因为他底层做了一些魔术,只要mysql中有的聚合函数,都可以通过func调用。

      session.query(func.count(User.id)).all()

    group_by 和 having:

    根据某个字段进行分组。比如想要根据性别进行分组,来统计每个分组分别有多少人,那么可以使用以下代码来完成:

    session.query(User.username,func.count(User.id)).group_by(User.username).all()

    having是对查找结果进一步过滤。比如只想要看未成年人的数量,那么可以首先对年龄进行分组统计人数,然后再对分组进行having过滤。示例代码如下:

    result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age >= 18).all()

我们在使用SQLAlchemy做数据的增删改查操作,我们是通过session对象来实现的。

  1. 构建session对象:所有和数据库的ORM操作都必须通过一个叫做session的会话对象来实现,通过以下代码来获取会话对象:

    from sqlalchemy.orm import sessionmaker
    
    engine = create_engine(DB_URI)
    session = sessionmaker(engine)()
  2. 添加对象:

    class User(Base):
        __tablename__ = 'user'
    
        id = Column(Integer,primary_key=True,autoincrement=True)
        name = Column(String(50))
        age = Column(Integer)
    • 创建对象,也即创建一条数据:

      u = User(name='xiaoning',age=18,country='china')
    • 将这个对象添加到session会话对象中:

      session.add(u)
    • 将session中的对象做commit操作(提交):

      session.commit()
    • 一次性添加多条数据:

      u1 = User(name='xiaoning',age=19,country='china')
      u2 = User(name='boke',age=20,country='china')
      session.add_all([u1,u2])
      session.commit()
  3. 查找对象:

    # 查找某个模型对应的那个表中所有的数据:
    all_user = session.query(User).all()
    # 使用filter_by来做条件查询
    all_user = session.query(User).filter_by(name='xiaoning').all()
    # 使用filter来做条件查询
    all_user = session.query(User).filter(User.name=='xiaoning').all()
    # 使用get方法查找数据,get方法是根据id来查找的,只会返回一条数据或者None
    user = session.query(User).get(primary_key)
    # 使用first方法获取结果集中的第一条数据
    user = session.query(User).first()

    小编在下一篇文章中将详细讲解查询。

    SQLAlchemy中filter()和filter_by()的区别
    1、filter引用列名时,使用“类名.属性名”的方式,比较使用两个等号“==”
    2、filter_by引用列名时,使用“属性名”,比较使用一个等号“=”
    3、在使用多条件匹配的时候,filter需要借助sqlalchemy里的and_ ; 而filter_by不需要,直接把多个匹配条件写在一起
    4、在使用多条件匹配时,用到>=、>、<=、<的情况,貌似不能使用filter_by。可能是姿势不对
  4. 修改对象:首先从数据库中查找对象,然后将这条数据修改为你想要的数据,最后做commit操作就可以修改数据了。

    user = session.query(User).first()
    user.name = 'boke'
    session.commit()
  5. 删除对象:将需要删除的数据从数据库中查找出来,然后使用session.delete方法将这条数据从session中删除,最后做commit操作就可以了。

    user = session.query(User).first()
    session.delete(user)
    session.commit()

SQLAlchemy连接数据库

使用SQLALchemy去连接数据库,其实就是需要使用一些配置信息,然后将他们组合成满足条件的字符串:# dialect+driver://username:password@host:port/database

HOSTNAME = '' # 主机地址
PORT = '3306' # 端口号
DATABASE = '' # 数据库
USERNAME = '' # 数据库账号
PASSWORD = '' # 数据库密码
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE) # 链接

然后使用create_engine创建一个引擎engine,然后再调用这个引擎的connect方法,就可以得到这个对象,然后就可以通过这个对象对数据库进行操作了:

engine = create_engine(DB_URI)

# 判断是否连接成功
conn = engine.connect()
result = conn.execute('select 1')
print(result.fetchone())

将ORM模型映射到数据库中,即创建表

  1. declarative_base根据engine创建一个ORM基类。

    from sqlalchemy.ext.declarative import declarative_base
    engine = create_engine(DB_URI)
    Base = declarative_base(engine)
  2. 用这个Base类作为基类来写自己的ORM类。要定义__tablename__类属性,来指定这个模型映射到数据库中的表名。

    class User(Base):
        __tablename__ = 'user'
  3. 创建属性来映射到表中的字段,所有需要映射到表中的属性都应该为Column类型:

    class User(Base):
        __tablename__ = 'user'
        # 2. 在这个ORM模型中创建一些属性,来跟表中的字段进行一一映射。这些属性必须是sqlalchemy给我们提供好的数据类型。
        id = Column(Integer,primary_key=True,autoincrement=True)
        name = Column(String(50))
        age = Column(Integer)
  4. 使用Base.metadata.create_all()来将模型映射到数据库中。
  5. 一旦使用Base.metadata.create_all()将模型映射到数据库中后,即使改变了模型的字段,也不会重新映射了。
  6. 可以使用Base.metadata.drop_all()将继承Base类的表从数据库中删除。

SQLAlchemy常用数据类型

  1. Integer:整形,映射到数据库中是int类型。
  2. Float:浮点类型,映射到数据库中是float类型。他占据的32位。
  3. Double:双精度浮点类型,映射到数据库中是double类型,占据64位。
  4. String:可变字符类型,映射到数据库中是varchar类型.
  5. Boolean:布尔类型,映射到数据库中的是tinyint类型。
  6. DECIMAL:定点类型。是专门为了解决浮点类型精度丢失的问题的。在存储钱相关的字段的时候建议大家都使用这个数据类型。并且这个类型使用的时候需要传递两个参数,第一个参数是用来标记这个字段总能能存储多少个数字,第二个参数表示小数点后有多少位。
  7. Enum:枚举类型。指定某个字段只能是枚举中指定的几个值,不能为其他值。在ORM模型中,使用Enum来作为枚举,示例代码如下:

    class Article(Base):
        __tablename__ = 'article'
        id = Column(Integer,primary_key=True,autoincrement=True)
        tag = Column(Enum("python",'flask','django'))

    在Python3中,已经内置了enum这个枚举的模块,我们也可以使用这个模块去定义相关的字段。示例代码如下:

    class TagEnum(enum.Enum):
        python = "python"
        flask = "flask"
        django = "django"
    
    class Article(Base):
        __tablename__ = 'article'
        id = Column(Integer,primary_key=True,autoincrement=True)
        tag = Column(Enum(TagEnum))
    
    article = Article(tag=TagEnum.flask)
  8. Date:存储时间,只能存储年月日。映射到数据库中是date类型。在Python代码中,可以使用datetime.date来指定。示例代码如下:

    class Article(Base):
        __tablename__ = 'article'
        id = Column(Integer,primary_key=True,autoincrement=True)
        create_time = Column(Date)
    
    article = Article(create_time=date(2017,10,10))
  9. DateTime:存储时间,可以存储年月日时分秒毫秒等。映射到数据库中也是datetime类型。在Python代码中,可以使用datetime.datetime来指定。示例代码如下:

    class Article(Base):
        __tablename__ = 'article'
        id = Column(Integer,primary_key=True,autoincrement=True)
        create_time = Column(DateTime)
    
    article = Article(create_time=datetime(2011,11,11,11,11,11))
  10. Time:存储时间,可以存储时分秒。映射到数据库中也是time类型。在Python代码中,可以使用datetime.time来至此那个。示例代码如下:

    class Article(Base):
        __tablename__ = 'article'
        id = Column(Integer,primary_key=True,autoincrement=True)
        create_time = Column(Time)
    
    article = Article(create_time=time(hour=11,minute=11,second=11))
  11. Text:存储长字符串。一般可以存储6W多个字符。如果超出了这个范围,可以使用LONGTEXT类型。映射到数据库中就是text类型。
  12. LONGTEXT:长文本类型,映射到数据库中是longtext类型。只能用于Mysql数据库。

Column常用参数

  1. primary_key:设置某个字段为主键。
  2. autoincrement:设置这个字段为自动增长的。
  3. default:设置某个字段的默认值。在发表时间这些字段上面经常用。
  4. nullable:指定某个字段是否为空。默认值是True,就是可以为空。
  5. unique:指定某个字段的值是否唯一。默认是False。
  6. onupdate:在数据更新的时候会调用这个参数指定的值或者函数。在第一次插入这条数据的时候,不会用onupdate的值,只会使用default的值。常用的就是update_time(每次更新数据的时候都要更新的值)。
  7. name:指定ORM模型中某个属性映射到表中的字段名。如果不指定,那么会使用这个属性的名字来作为字段名。如果指定了,就会使用指定的这个值作为参数。这个参数也可以当作位置参数,在第1个参数来指定。
  8. comment:在数据库中的注释。

Flask开启debug模式的几种方式:

  1. app.run(debug=True)中传递一个参数debug=True就可以开启DEBUG模式。
  2. 设置app.deubg=True,就可以开启debug模式。
  3. 通过配置参数的形式设置DEBUG模式:app.config.update(DEBUG=True)
  4. 通过配置文件的形式设置DEBUG模式:。
    新建一个config.py文件:

    #encoding: utf-8
    DEBUG=True

    导入

    import config
    app.config.from_object(config)

微信小程序swiper组件中当数据少于display-multiple-items设置的数,就会出现这个不显示这个问题在社区看到在2019年的8月份已经有人提出了,官方说的是:目前可以通过追加空的swiper-item解决,我们也在想办法优化这块能力。这显然不是我们想要的结果,空的swiper-item,就会显示空白。
首先我们来分析下问题:当swiper组件中当数据少于display-multiple-items设置的数量的时候才会出现这样的问题,我们假设我们要显示3个。

display-multiple-items设置的数swiper组件中当数据显示个数是否正常
343
333
222
111
000

通过这个表格我们就可以很清楚的发现,当swiper组件中当数据数大于或则等于display-multiple-items设置的数的时候,就会显示正常。那么我们就可以动态的设计display-multiple-items的数量,如果swiper组件中当数据数大于或则等于display-multiple-items设置的数的时候,我们就显示我们要限定的数,否则就显示display-multiple-items的数量。这样我们就可以完美的绕开这个问题了。同时宽度(或者高度)我们也采用这种的方式来进行动态的设置就可以了。
示例代码:

<swiper style="width: 90%; height: {{datas.length>2?'330':datas.length*110}}rpx; vertical="true" autoplay="true" circular="true" interval="2000" display-multiple-items="{{datas.length>2?3:datas.length}}">
    <block wx:for="{{datas}}">
        <swiper-item>
                <image src="{{item.avatar}}" style="width: 70rpx; height: 70rpx;min-width: 70rpx;min-height: 70rpx;" />
        </swiper-item>
    </block>
</swiper>

微信小程序中swiper组件禁止用户上下滑动这个实现起来比较的简单,我们通过手册会发现,该组件的swiper-item里面上下滑动会执行函数catchtouchmove,所以我们可以通过控制这个函数来实现

< swiper-item catchtouchmove=“stopTouchMove” >< swiper-item >
stopTouchMove: function() {
    return false;
}

这种方法可以阻止手动滑动,但是带来的影响是:页面不能滑动了。这是由于在你上下滑动的时候,仍然会执行滑动的这个动作,但是触发的函数没有进行任何的操作,如果我们想让页面也滑动,我们采用下面的方法。

给这个区域一个模板压在上面,但是该组件本身就应用了定位,那么我们可以采用,前置方法:

<swiper class="swiper-disabled">
    ......               
</swiper>
.swiper-disabled {
    position: relative;
}

.swiper-disabled::after {
    position: absolute;
    content: '';
    top: 0;
    left: 0;
    width: 100%;
}

这样我们就解决了这个问题了。

解决Typecho迁移服务器出现"Database Server Error"错误,小编在迁移Typecho,出现了这样的问题,首先排查掉数据库账号密码等问题,如果你的连接地址,数据库用户名,数据库密码错误的话,那肯定是不行的,如果这些都没有问题,还是出现这样的问题,我来说下怎么解决。
Typecho的数据库配置是在网站的根目录下面的config.inc.php这个文件里面,我们的链接地址,数据库用户名,密码也是在这里修改。
出现Database Server Error这个错误有的时候是由于Typecho_Db这个写错了,只需要将Mysql换成Pdo_Mysql就可以了。
解决Typecho迁移服务器出现%22Database Server Error%22错误.png

微信小程序现在可以开通直播功能,只要符合资质的都可以开通直播。开通该功能后,我们只需要按照文档里面说明的方式开发就好了。
首先我们引入【直播组件】 live-player-plugin
分为两种方式引入,一种是在主包中引入,另一种是在分包中引入。因为直播组件不计入代码包体积,所以小编建议大家在主包引入,而且还有些功能只能在主包中使用,这个也是看大家的需求。
引入方式,在app.json里面引入,json文件里面不能写注释,大家在引入的时候记得把注释删除掉:

  • 主包引入

    "plugins": {
          "live-player-plugin": {
              "version": "1.0.5", // 注意填写该直播组件最新版本号,微信开发者工具调试时可获取最新版本号(复制时请去掉注释)小编在开发的时候版本是1.0.5
              "provider": "wx2b03c6e691cd7370" // 必须填该直播组件appid,该示例值即为直播组件appid(复制时请去掉注释)
          }
      }
  • 分包引入

    "subpackages": [
          {
              "plugins": {
                  "live-player-plugin": {
                      "version": "1.0.5", // 注意该直播组件最新版本号,微信开发者工具调试时可获取最新版本号(复制时请去掉注释)
                      "provider": "wx2b03c6e691cd7370" // 必须填该直播组件appid,该示例值即为直播组件appid(复制时请去掉注释)
                  }
              }
          }
      ]

接下来我们就要进入直播间了,不需要我们写直播的界面,只需要跳转到直播组件就可以了。分享官方也给封装好了,只需要拿来使用就可以了,跳转方式也有两种,房间号在你创建完直播间的时候就有了。

  • 直接通过navigator进行跳转

    let roomId = [直播房间id] // 房间号
      let customParams = { path: 'pages/index/index', pid: 1 } // 开发者在直播间页面路径上携带自定义参数(如示例中的path和pid参数),后续可以在分享卡片链接和跳转至商详页时获取,详见【获取自定义参数】、【直播间到商详页面携带参数】章节
      this.setData({
          roomId,
          customParams: encodeURIComponent(JSON.stringify(customParams))
      })
      <navigator url="plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id={{roomId}}&custom_params={{customParams}}"></navigator>
      // 其中wx2b03c6e691cd7370是直播组件appid不能修改
  • js中跳转

    let roomId = [直播房间id] // 房间号
      let customParams = { path: 'pages/index/index', pid: 1 } // 开发者在直播间页面路径上携带自定义参数(如示例中的path和pid参数),后续可以在分享卡片链接和跳转至商详页时获取,详见【获取自定义参数】、【直播间到商详页面携带参数】章节
      wx.navigateTo({
          url: `plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=${roomId}&custom_params=${encodeURIComponent(JSON.stringify(customParams))}`
      })
      // 其中wx2b03c6e691cd7370是直播组件appid不能修改

另外在说一下获取直播间列表的方法、

【获取直播房间列表】接口,仅供后台调用
接口规则:该接口仅供商家后台调用,调用限额 500 次/天,建议开发者自己做缓存(此接口与下面【获取回放视频】接口共用 500 次/天限制,请合理分配调用频次)。

请求URL: http://api.weixin.qq.com/wxa/business/getliveinfo?access_token=

请求方式: POST

请求示例:

  • Request
    {
        "start": 0, // 起始拉取房间,start = 0 表示从第 1 个房间开始拉取
        "limit": 10 // 每次拉取的个数上限,不要设置过大,建议 100 以内
    }

Response(官方文档可能有问题,anchor_img这个没返回,返回的是share_img)

    {
        "errcode": 0, // errcode = 0 代表成功;errcode = 1 代表未创建直播房间
        "errmsg": "ok",
        "room_info": [{
        "name": "直播房间名",
        "roomid": 1,
        "cover_img": "http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/Rl1RuuhdstSfZa8EEljedAYcbtX3Ejpdl2et1tPAQ37bdicnxoVialDLCKKDcPBy8Iic0kCiaiaalXg3EbpNKoicrweQ\/0?wx_fmt=jpeg",
        "live_status": 101,
        "start_time": 1568128900,
        "end_time": 1568131200,
        "anchor_name": "李四",
        "anchor_img": "http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/Rl1RuuhdstSfZa8EEljedAYcbtX3Ejpdlp0sf9YTorOzUbGF9Eib6ic54k9fX0xreAIt35HCeiakO04yCwymoKTjw\/0?wx_fmt=jpeg",
        "goods": [          
            {
                "cover_img": "http://mmbiz.qpic.cn/mmbiz_png/FVribAGdErI2PmyST9ZM0JLbNM48I7TH2FlrwYOlnYqGaej8qKubG1EvK0QIkkwqvicrYTzVtjKmSZSeY5ianc3mw/0?wx_fmt=png",
                "url": "pages/index/index.html",
                "price": 1100,
                "name": "fdgfgf"
            }
        ],
        "total": 1
    }

常用的就这些了,要是有需要小编说明的,欢迎在下方留言。
微信小程序开通直播功能.jpeg

微信小程序客服会话发送页面卡片,这个腾讯在按钮里面已经封装好了,我们直接拿过来用就行了。
首先设置open-type="contact"
我们看下官方文档
官方文档.png

常用的就这几个

open-type="contact" 
send-message-title=""
show-message-card="" 
send-message-path=""

微信小程序客服会话发送页面卡片.jpeg

微信小程序获取用户收货地址,这个功能在我们开发商城的时候,经常会用到,所以微信小程序专门提供了API,我们只需要直接调用就可以了。
实现代码:

getAddress: function() {
        let that = this;
        wx.chooseAddress({
            success(res) {
                console.error(res)
                console.log(res.userName)//收货人姓名
                console.log(res.postalCode)//邮编
                console.log(res.provinceName)//国标收货地址第一级地址
                console.log(res.cityName)//国标收货地址第二级地址
                console.log(res.countyName)//国标收货地址第三级地址
                console.log(res.detailInfo)//详细收货地址信息
                console.log(res.nationalCode)//收货地址国家码
                console.log(res.telNumber)//收货人手机号码
            }
        })
    },

实现效果:
收货地址.png
你只要对你自己的内容进行赋值就可以了。

微信小程序获取用户收货地址.jpeg