2017年3月

python3使用SQLAlchemy操作数据库

软硬件环境

  • Windows 10
  • Python 3.5.1
  • mysql 5.6
  • sqlalchemy

前言

前文python3中的mysql数据库操作已经介绍过利用pymysql来操作mysql数据库,本文介绍一个ORM框架SQLAlchemy,它可以帮助我们更加优雅、更加高效的实现数据库操作,而且还不限于mysql。

什么是ORM

ORM即Object Rational Mapping,对象关系映射。百度百科中是这样解释的

对象-关系映射(OBJECT RELATIONAL MAPPING,简称ORM),是随着面向对象的软件开发方法发展而产生的。用来把对象模型表示的对象映射到基于SQL的关系模型数据库结构中去。这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作实体对象的属性和方法。ORM技术是在对象和关系之间提供了一条桥梁,前台的对象型数据和数据库中的关系型的数据通过这个桥梁来相互转化。

用一句话来概括就是,把关系数据库的表结构映射到对象上。操作对象的属性就等于操作数据库中的记录。

SQLAlchemy实践

在写代码之前,我们先准备下数据库,这里还是以mysql为例,其它的数据库也类似,可以参靠sqlalchemy的官方文档。利用mysql-workbench图形化工具创建,表结构如下图所示,

sqlalchemy_01

接下来,安装相关的工具包

pip3 install mysql-connector
pip3 install pymsql
pip3 install sqlalchemy

最后来写代码

# -*- coding: utf-8 -*-

"""
@version: ??
@author: djstava
@license: MIT Licence 
@contact: djstava@gmail.com
@site: http://www.xugaoxiang.com/blog
@software: PyCharm
@file: SQLAlchemy.py
@time: 2017/3/22 10:42
"""

from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 创建对象的基类:
Base = declarative_base()

# 定义Channel对象:
class Channel(Base):
    
    # 表名
    __tablename__ = 'playback'
    
    # 表结构
    id = Column(String(20),primary_key=True)
    channel_name = Column(String(45))
    address = Column(String(80))
    service_name = Column(String(45))
    
    def __init__(self,id,channel_name,address,service_name):
        self.id = id
        self.channel_name = channel_name
        self.address = address
        self.service_name = service_name

# 初始化数据库连接,:
engine = create_engine('mysql+mysqlconnector://root:toor@localhost:3306/troutling')

# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)

session = DBSession()

# 增操作
item1 = Channel(id='1',channel_name='catv1',address='http://10.10.10.188/catv1',service_name='news')
session.add(item1)

item2 = Channel(id='2',channel_name='catv2',address='http://10.10.10.188/catv2',service_name='sports')
session.add(item2)

item3 = Channel(id='3',channel_name='catv3',address='http://10.10.10.188/catv3',service_name='economics')
session.add(item3)

session.commit()
session.close()

# 查操作
session1 = DBSession()
channel = session1.query(Channel).filter(Channel.id < '4').all()

for i in range(len(channel)):
    print(channel[i].id)
    print(channel[i].channel_name)
    print(channel[i].address)
    print(channel[i].service_name)

session1.close()

# 改操作
session2 = DBSession()
session2.query(Channel).filter(Channel.id == '2').update({Channel.service_name: 'movie'}, synchronize_session=False)
session2.commit()
session2.close()

## 查看修改结果
session3 = DBSession()
print('\n')
print(session3.query(Channel).filter(Channel.id == '2').one().service_name)
session3.close()

# 删操作
session4 = DBSession()
session4.query(Channel).filter(Channel.id == '3').delete()
session4.commit()
session4.close()

执行上述脚本得到

D:\tools\python3.5.1\python.exe D:/workshop/github/ffmpegWrapper/SQLAlchemy.py
1
catv1
http://10.10.10.188/catv1
news
2
catv2
http://10.10.10.188/catv2
sports
3
catv3
http://10.10.10.188/catv3
economics


movie

Process finished with exit code 0

然后用mysql-workbench查看数据库

sqlalchemy_02

数据库中的记录跟代码要实现的意图完全相符。

参考资料

  1. http://www.sqlalchemy.org/
  2. http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014320114981139589ac5f02944601ae22834e9c521415000
  3. http://baike.baidu.com/link?url=enj6JgEqdyte0DLpJqBAfiKusns6yL3-MHU8pW6_j14sa0yAvuTtC3DMlkHKbasHOti50UbcSLxljOVm5w6fV_

PyQt5系列教程(十二)pyinstaller打包exe时subprocess无效的解决方法

软硬件环境

  • Windows 10
  • Python 3.5.2
  • PyQt5
  • pyinstaller

前言

前面一篇博文PyQt5系列教程(十)pyinstaller打包exe已经介绍过如何使用pyinstaller打包exe,最近在打包包含subprocess.Popen时发现,加上参数—noconsole时产生的exe文件在运行的时候,进程并没有正确运行。经过一番google,问题得以解决,现将解决方法记录一下,形成此文。

subprocess的使用

我这里需要利用subprocess.Popen创建一个进程去执行一个命令行操作,

mProcess = subprocess.Popen(cmd,stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True)

pyinstaller打包操作命令如下

pyinstaller -F --noconsole --clean --distpath release bin\\troutling

打包后生成的exe,可以运行,不过查看进程并没有如预期正确地工作。

解决方法

在创建进程时,加上startupinfo参数,如下

si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
mProcess = subprocess.Popen(cmd,stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True,startupinfo=si)

问题完美解决,具体可以参考下参考资料

参考资料

1 https://github.com/pyinstaller/pyinstaller/wiki/Recipe-subprocess

2 https://github.com/djstava/troutling

PyQt5系列教程(十一)发送信号时传参

软硬件环境

  • Windows 10
  • PyQt5
  • Python3.4

前言

在PyQt5编程中,经常需要在某个signal发送时附带相应的数据,实际上就是传参,然后在slot方法中接收传递过来的数据,这样就可以非常灵活地实现一些业务逻辑。好了,本文就来实现这个功能。

实践

首先是生成一个signal

transcoding_thread_status = pyqtSignal(object)

然后将signal和slot方法绑定

self.transcoding_thread_status.connect(self.slotShowTransThreadStatus)

slot方法接收数据

def slotShowTransThreadStatus(something):
    print(something)

最后来看看,signal emit时是怎么实现的

self.transcoding_thread_status.emit("Hello")

至此数据就传递成功了,就是这么简单。

以上是传递一个参数,那如果我需要传递2个呢,是不是也可以用上面的方法呢?思路是一样的,细节做一点小修改就好了。

transcoding_thread_status = pyqtSignal(str,str)

如果传递的数据类型是整形的话,就换成int,对应的slot方法也要跟着修改

def slotShowTransThreadStatus(something,anything):
    print(something)
    print(anything)

发送信号时,就跟上2个参数

self.transcoding_thread_status.emit("Hello","world")

类似的,如果需要传递更多参数,请依葫芦画瓢。

源码下载

https://github.com/djstava/troutling,这个项目是一个带GUI的ffmpeg wrapper。因为最近正在做一个电视直播的项目,其中涉及到音视频的实时再编码及HLS相关的内容,为了更加方便的进行节目源(目前是UDP的流)转码,就做了个这个小工具。使用的是Windows+PyQt5+Python3。

PyQt5系列教程(十)pyinstaller打包exe

软硬件环境

  • Windows 10
  • PyQt5
  • Python3.4
  • pyinstaller

前言

前文PyQt5系列教程(三)用py2exe进行程序打包介绍了如何使用py2exe来给python3工程打包,本文介绍另一个打包工具pyinstaller,个人感觉比py2exe更加简单、方便。

pyinstaller安装

命令行中执行

pip3 install pyinstaller

打包exe

工程还是以之前的为例,下载地址是http://download.csdn.net/detail/djstavav/9351205,解压进入工程目录,命令行执行打包命令

pyinstaller -F --distpath release main.py

pyinstaller_01

pyinstaller_02

pyinstaller_03

pyinstaller的打包参数很多,需要的话通过help来查看

pyinstaller -h

参考资料

1、http://www.pyinstaller.org/