sqlalchemy 总结

1、基本简介

1.1 为什么要用sqlalchemy,直接用pymysql 或者cx_oracle 不香吗?

orm 框架 和sqlalchemy
简单来说就是orm 框架就是用类的方式来管理数据库。把每一行数据看作一个对象。
sqlalchemy 是orm 比较常用的框架 。

参见大神的解释。

2、基本操作

参考资料

2.1 初始化连接 需要用到两个包
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine('mysql://pass@localhost/test',echo=True)
DBSession = sessionmaker(bind=engine)
session = DBSession()
ret=session.execute('desc user')
print ret
# print ret.fetchall()
print ret.first()

注意在这个create_engine 中
engine = create_engine('mysql://pass@localhost/test',echo=True)
参数为 数据库连接类型 :// user : password @ ip地址(可加[:端口])/ 数据库
例如:

有时候还在会后面加上 connect_args ={'charset':'utf8'}
session 就相当于游标

2.2 创建表
from sqlalchemy import Column
from sqlalchemy.types import *
from sqlalchemy.ext.declarative import declarative_base

BaseModel = declarative_base()

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine('mysql://root:Hs2BitqLYKoruZJbT8SV@localhost/test')
DBSession = sessionmaker(bind=engine)


class User(BaseModel):
    __tablename__ = 'user1'  # 表名
    user_name = Column(CHAR(30), primary_key=True)
    pwd = Column(VARCHAR(20), default='aaa', nullable=False)
    age = Column(SMALLINT(), server_default='12')
    accout = Column(INT())
    birthday = Column(TIMESTAMP())
    article = Column(TEXT())
    height = Column(FLOAT())
def init_db():
    '''
    初始化数据库
    :return:
    '''
    BaseModel.metadata.create_all(engine)


def drop_db():
    '''
    删除所有数据表
    :return:
    '''
    BaseModel.metadata.drop_all(engine)


drop_db()
init_db()

一旦表被创建了,修改User类不能改变数据库结构,只能用sql语句或删除表再创建来修改数据库结构

2.3.添加记录
user1=User(user_name='lujianxing',accout=1245678)
session.add(user1)
session.commit()

要commit才能起作用

2.4.更新记录
  • 2.4.1.更新单条记录
query = session.query(User) 
user = query.get('lujianxing11')
print user.accout
user.accout='987'
session.flush()
  • 2.4.2.更新多条记录
query = session.query(User)
query.filter(User.user_name=='lujianxing2').update({User.age: '15'})
query.filter(User.user_name=='lujianxing2').update({'age': '16'})
query.filter(User.pwd=='aaa').update({'age': '17'})
2.5.删除记录
query = session.query(User)
user = query.get('lujianxing11')
session.delete(user)
session.flush()
2.6.查询(最重要)
query = session.query(User)
print (query ) # 只显示sql语句,不会执行查询(!!!工程中经常用!!!)
print (query[0] ) # 执行查询
print (query.all())  # 执行查询
print (query.first())  # 执行查询
for user in query:  # 执行查询
    print (user.user_name)
  • 高级一点的查询:
# 筛选
user = query.get(1) # 根据主键获取
print query.filter(User.user_name == 2)  # 只显示sql语句,不会执行查询
print query.filter(User.user_name == 'lujianxing').all()  # 执行查询
print query.filter(User.user_name == 'lujianxing', User.accout == 1245678, User.age > 10).all()  # 执行查询
print query.filter(User.user_name == 'lujianxing').filter(User.accout == 1245678).all()
print query.filter("user_name = 'lujianxing'").all()  # 执行查询
print query.filter("user_name = 'lujianxing' and accout=1245678").all()  # 执行查询
query2 = session.query(User.user_name)  # 返回的结果不是User的实例,而是元组
print query2.all()  # 执行查询
print query2.offset(1).limit(1).all()  # 等于 limit 1,1
# 排序
print query2.order_by(User.user_name).all()  
print query2.order_by('user_name').all()  
print query2.order_by(User.user_name.desc()).all()
print query2.order_by(User.user_name, User.accout.desc()).all()
print query2.filter("user_name = 'lujianxing' and accout=1245678").count()
# 聚合查询
print session.query(func.count('*')).select_from(User).scalar()
print session.query(func.count('1')).select_from(User).scalar()
print session.query(func.count(User.id)).scalar()
print session.query(func.count('*')).filter(User.id > 0).scalar() # filter() 中包含 User,因此不需要指定表
print session.query(func.count('*')).filter(User.name == 'a').limit(1).scalar() == 1 # 可以用 limit() 限制 count() 的返回数
print session.query(func.sum(User.id)).scalar()
print session.query(func.now()).scalar() # func 后可以跟任意函数名,只要该数据库支持
print session.query(func.current_timestamp()).scalar()
print session.query(func.md5(User.name)).filter(User.id == 1).scalar()

3、项目常用操作方法

项目文件结构如下:


image.png

主要是为了批量查询,所以已经假设很多表已经建好,存好。

3.1. base_field.py (定义表的类)
from sqlalchemy import Column
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.types  import Float,VARCHAR,String,Numeric,DateTime,Integer,NVARCHAR
Base = declarative_base()
## j假设存在的表为User

## 定义表的类
class User(Base):
    # 表的名字:
    __tablename__ = 'user'

    # 表的结构:
    id = Column(String(20), primary_key=True) # 一定要设这个主键
    name = Column(String(20))

在这个文件里,可以设置很多的表的类,统一定义

3.2. get_base_data.py(取数)
from sqlalchemy import  create_engine
from sqlalchemy.orm import sessionmaker
import pandas as pd
## 导入base_field 中的表
from get_data.base_field import User
from sqlalchemy_project import singleton  ## 3.4 会讲

## 定义取数的地址和游标
@ singleton  ## 3.4 中会讲
class BaseData(object):
  def __init__(self):
      host = '0.0.0.0'
      user= 'user'
      password ='pass'
      database = 'db'
      # charset = 'utf8'
      self.engine = create_engine('mssql+pymssql://'+
                                  user + ":"+
                                  password + "@"+
                                  host +'/'+
                                  database)
      self.Session = sessionmaker(bind=self.engine)
      self.session  =self.Session()

class GetBaseData(object):
  def __init__(self,base_data):# 传进去一个实例
      self.engine = base_data.engine
      self.session = base_data.session

  # 开始查询数据
  def get_query_data(self):
      query = self.session.query(User).filter(User.name =='tom')

      df = pd.read_sql(query.statement,self.engine)
  
      return df 
3.3. main_file.py(主文件)
from get_data.get_base_data import BaseData,GetBaseData
if __name__ =='__main__':
    base_data = BaseData()
    base_data_obj =  GetBaseData(base_data)
    df = base_data_obj.get_query_data()
    print(df)
3.4 singleton (限制一个实例是一样的)

在主文件下放一个这singleton.py 的文件

# -*- coding: utf-8 -*-
from functools import  wraps
def singleton(cls):
    instances = {}
    @wraps(cls)
    def get_instance(*args,**kw):
        if cls not in instances:
            instances[cls] = cls(*args,**kw)
        return instances[cls]
    return get_instance

具体的原理 ,后面会专门出一个。(列上链接的地方)

4 sqlalchemy 插入df数据

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

# ------------------------------
# @Time    : 2020/7/16
# @Author  : wangyd
# @File    : insert_df.py
# @Project : sqlalchemy insert database
# ------------------------------

from sqlalchemy import types
import sqlalchemy
import os
import pandas as pd

os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.AL32UTF8'

# sqlserver
engine = sqlalchemy.create_engine('mssql+pymssql://user:password@ip/database',
                                 connect_args={'charset':'utf8'})

data=pd.DataFrame({'a':[1,2,3,4],'b':['a','b','c','d']})

## 注意这一步要变成大写
data.columns = [x.upper()for x in data.columns]

## tosql
dtypes= {}
# 注意下面的是小写
dtypes['a'] = types.Numeric(20,4)
dtypes['b'] = types.VARCHAR(4)

# 插入数据库,注意TABLE_NAME 大写,这个表需要提前在数据库中创建好
data.to_sql('TABLE_NAME',con=engine,if_exists='append',index=False,
            dtypes= dtypes,index_label=None)

注意大小写

在type[小写] 其他数据都大写

5、注意事项

5.1 主键

在取数的过程中,使用sqlchemy 调用数据的过程,必须在原表中增加 primary key 。所有在data_base_field 中也得在主键后面增加 primary key

5.2 主键

可以从sqlalchemy 中导入 func_,_or 等方便查询辅助的函数

6、sqlalchemy filter 总结

参考资料

from flask import Flask, jsonify, json
from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func, and_, or_
 
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime
 
 
# 连接数据库字符串
DB_URI = "mysql://root:123456@127.0.0.1/pyDemo"
 
engine = create_engine(DB_URI)
# 判断是否连接成功
engine.connect()
 
 
# 创建ORM
Base = declarative_base(engine)
 
# 创建回话
session = sessionmaker(engine)()
 
 
class Article(Base):
    # 表名字
    __tablename__ = 'Article'
    # 列
    id = Column(Integer, primary_key=True, autoincrement=True)
    # read_count = Column(Integer, default=0)
    title = Column(String(50), default='1111')
    content = Column(String(50))
    price = Column(Float, nullable=False)
 
 
 
# 查询条件
# 1.equal
res = session.query(Article).filter(Article.id == 21).first()
# print(res)
 
# 2.notequal
res = session.query(Article).filter(Article.id != 21).all()
# print(res)
 
# 3.like & ilike不区分大小写
res = session.query(Article).filter(Article.title.like('title%')).all()
# print(res)
 
# 4.in
res = session.query(Article).filter(Article.title.in_(['title0', 'title1'])).all()
# print(res)
 
# 5.not in
res = session.query(Article).filter(~Article.title.in_(['title0', 'title1'])).all()
# print(res)
res = session.query(Article).filter(Article.title.notin_(['title0', 'title1'])).all()
# print(res)
 
# 6.isnull
res = session.query(Article).filter(Article.content == None).all()
# print(res)
 
# 7.is not null
res = session.query(Article).filter(Article.content != None).all()
# print(res)
 
# 8 and
res = session.query(Article).filter(Article.content == None, Article.title.notin_(['title0', 'title1'])).all()
# print(res)
res = session.query(Article).filter(and_(Article.content == None, Article.title.notin_(['title0', 'title1']))).all()
# print(res)
 
# 9 or
res = session.query(Article).filter(
    or_(Article.content != None, Article.title.notin_(['title0', 'title1', 'title5']))).all()
print(res)

参考资料

注意问题

1、oracle 数据库中读取数据,如果中文,需要设置编码
记录一个成功的写法,借助cx_Oracle,

import cx_Oracle 
create_orgine("oracle+cx_oracle://user:password@host/database",connect_args = {
'encoding' = 'UTF-8',
'nencoding'  = 'UTF-8',
'events' = True)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352