乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      SQLAlchemy詳細教程

       只怕想不到 2015-09-14

      前言:最近開始學(xué)習(xí)SQLAlchemy,本教程是其官方文檔以及在讀英文版<Essential SQLAlchemy>的翻譯加一些自己的理解和總結(jié)

      1 什么是 SQLAlchemy?

      它是給mysql, oracle,sqlite等關(guān)系型數(shù)據(jù)庫的python接口,不需要大幅修改原有的python代碼,它已經(jīng)包含了SQL表達式語言和ORM,看一些例子:

      sql=”INSERT INTO user(user_name, password) VALUES (%s, %s)”
      cursor = conn.cursor()
      cursor.execute(sql, (‘dongwm’, ‘testpass’))

      以上是一個常用的mysql的SQL語句,但是冗長也容易出錯,并且可能導(dǎo)致安全問題(因為是字符串的語句,會存在SQL注入),并且代碼不跨平臺,在不同數(shù)據(jù)庫軟件的語句不同(以下是一個 Oracle例子),不具備客移植性:

      sql=”INSERT INTO user(user_name, password) VALUES (:1, :2)”
      cursor = conn.cursor()
      cursor.execute(sql, ‘dongwm’, ‘testpass’)

      而在SQLAlchemy里只需要這樣寫:

      statement = user_table.insert(user_name=’rick’, password=’parrot’)
      statement.execute()  #護略是什么數(shù)據(jù)庫環(huán)境

      SQLAlchemy還能讓你寫出很pythonic的語句:

      statement = user_table.select(and_(
      user_table.c.created >= date(2007,1,1),
      user_table.c.created < date(2008,1,1))
      result = statement.execute()  #檢索所有在2007年創(chuàng)建的用戶

      metadata=MetaData(‘sqlite://’) # 告訴它你設(shè)置的數(shù)據(jù)庫類型是基于內(nèi)存的sqlite
      user_table = Table(  #創(chuàng)建一個表
      ‘tf_user’, metadata,
      Column(‘id’, Integer, primary_key=True),  #一些字段,假設(shè)你懂SQL,那么以下的字段很好理解
      Column(‘user_name’, Unicode(16), unique=True, nullable=False),
      Column(‘email_address’, Unicode(255), unique=True, nullable=False),
      Column(‘password’, Unicode(40), nullable=False),
      Column(‘first_name’, Unicode(255), default=”),
      Column(‘last_name’, Unicode(255), default=”),
      Column(‘created’, DateTime, default=datetime.now))

      users_table = Table(‘users’, metadata, autoload=True) #假設(shè)table已經(jīng)存在.就不需要指定字段,只是加個autoload=True

      class User(object): pass  #雖然SQLAlchemy強大,但是插入更新還是需要手動指定,可以使用ORM,方法就是:設(shè)定一個類,定義一個表,把表映射到類里面
      mapper(User, user_table)

      下面是一個完整ORM的例子:

      Source code

         

      from sqlalchemy.orm import mapper, sessionmaker #sessionmaker()函數(shù)是最常使用的創(chuàng)建最頂層可用于整個應(yīng)用Session 的方法,Session管理著所有與數(shù)據(jù)庫之間的會話

      from datetime import datetime

      from sqlalchemy import Table, MetaData, Column,ForeignKey, Integer, String, Unicode, DateTime #會SQL的人能理解這些函數(shù)吧?

      engine = create_engine("sqlite:///tutorial.db",echo=True) #創(chuàng)建到數(shù)據(jù)庫的連接,echo=True表示用logging輸出調(diào)試結(jié)果

      metadata = MetaData() #跟蹤表屬性

      user_table = Table( #創(chuàng)建一個表所需的信息:字段,表名等

      'tf_user', metadata,

      Column('id', Integer, primary_key=True),

      Column('user_name', Unicode(16), unique=True,nullable=False),

      Column('email_address', Unicode(255), unique=True,nullable=False),

      Column('password', Unicode(40), nullable=False),

      Column('first_name', Unicode(255), default=''),

      Column('last_name', Unicode(255), default=''),

      Column('created', DateTime, default=datetime.now))

      metadata.create_all(engine)  #在數(shù)據(jù)庫中生成表

      class User(object): pass #創(chuàng)建一個映射類

      mapper(User, user_table) #把表映射到類

      Session = sessionmaker() #創(chuàng)建了一個自定義了的 Session類

      Session.configure(bind=engine)  #將創(chuàng)建的數(shù)據(jù)庫連接關(guān)聯(lián)到這個session

      session = Session()

      u = User()

      u.user_name='dongwm'

      u.email_address='dongwm@dongwm.com'

      u.password='testpass' #給映射類添加以下必要的屬性,因為上面創(chuàng)建表指定這幾個字段不能為空

      session.add(u) #在session中添加內(nèi)容

       

      session.flush() #保存數(shù)據(jù)

      session.commit() #數(shù)據(jù)庫事務(wù)的提交,sisson自動過期而不需要關(guān)閉

       

      query = session.query(User) #query() 簡單的理解就是select() 的支持 ORM 的替代方法,可以接受任意組合的 class/column 表達式

      print list(query) #列出所有user

      print query.get(1) #根據(jù)主鍵顯示

      print query.filter_by(user_name='dongwm').first()  #類似于SQL的where,打印其中的第一個

      u = query.filter_by(user_name='dongwm').first()

      u.password = 'newpass' #修改其密碼字段

      session.commit() #提交事務(wù)

      print query.get(1).password #打印會出現(xiàn)新密碼

       

      for instance insession.query(User).order_by(User.id):  #根據(jù)id字段排序,打印其中的用戶名和郵箱地址

          printinstance.user_name, instance.email_address

      既然是ORM框架,我們來一個更復(fù)雜的包含關(guān)系的例子,先看sql語句:

      CREATE TABLE tf_user (
      id INTEGER NOT NULL,
      user_name VARCHAR(16) NOT NULL,
      email_address VARCHAR(255) NOT NULL,
      password VARCHAR(40) NOT NULL,
      first_name VARCHAR(255),
      last_name VARCHAR(255),
      created TIMESTAMP,
      PRIMARY KEY (id),
      UNIQUE (user_name),
      UNIQUE (email_address));
      CREATE TABLE tf_group (
      id INTEGER NOT NULL,
      group_name VARCHAR(16) NOT NULL,
      PRIMARY KEY (id),
      UNIQUE (group_name));
      CREATE TABLE tf_permission (
      id INTEGER NOT NULL,
      permission_name VARCHAR(16) NOT NULL,
      PRIMARY KEY (id),
      UNIQUE (permission_name));
      CREATE TABLE user_group (
      user_id INTEGER,
      group_id INTEGER,
      PRIMARY KEY(user_id, group_id),
      FOREIGN KEY(user_id) REFERENCES tf_user (id), #user_group的user_id關(guān)聯(lián)了tf_user的id字段
      FOREIGN KEY(group_id) REFERENCES tf_group (id));  #group_id關(guān)聯(lián)了 tf_group 的id字段

      CREATE TABLE group_permission (
      group_id INTEGER,
      permission_id INTEGER,
      PRIMARY KEY(group_id, permission_id),
      FOREIGN KEY(group_id) REFERENCES tf_group (id),  #group_permission的id關(guān)聯(lián) tf_group的id字段
      FOREIGN KEY(permission_id) REFERENCES tf_permission (id)); #permission_id關(guān)聯(lián)了tf_permission 的id字段

      這是一個復(fù)雜的多對多的關(guān)系,比如檢查用戶是否有admin權(quán)限,sql需要這樣:

      SELECT COUNT(*) FROM tf_user, tf_group, tf_permission WHERE
      tf_user.user_name=’dongwm’ AND tf_user.id=user_group.user_id
      AND user_group.group_id = group_permission.group_id
      AND group_permission.permission_id = tf_permission.id
      AND permission_name=’admin’;  看起來太復(fù)雜并且繁長了

      在面向?qū)ο蟮氖澜缋?是這樣的:

      class User(object):
      groups=[]
      class Group(object):
      users=[]
      permissions=[]
      class Permission(object):
      groups=[]

      Source code

         

      print 'Summary for %s' % user.user_name

      for g in user.groups:

          print 'Member of group %s' % g.group_name

          for p ing.permissions:

              print'... which has permission %s' % p.permission_name

       

      Source code

         

      def user_has_permission(user, permission_name):  #檢查用戶是否有permission_name的權(quán)限的函數(shù)

          for g inuser.groups:

              for p ing.permissions: #可以看出來使用了for循環(huán)

                  ifp.permission_name == 'admin':

                     return True

          return False

      而在SQLAlchemy中,這樣做:

      mapper(User, user_table, properties=dict(
      groups=relation(Group, secondary=user_group, backref=’users’))) #properties是一個字典值。增加了一個groups 值,它又是一個relation 對象,這個對象實現(xiàn)

      #了Group類與user_group的  映射。這樣我通過user_table的groups 屬性就可以反映出RssFeed的值來,

      #中間表對象(user_group)傳給secondary參數(shù),backref為自己的表(users)
      mapper(Group, group_table, properties=dict(
      permissions=relation(Permission, secondary=group_permission,
      backref=’groups’)))
      mapper(Permission, permission_table)

       

      q = session.query(Permission)
      dongwm_is_admin = q.count_by(permission_name=’admin’,user_name=’dongwm’)

      假如計算組里用戶數(shù)(不包含忘記刪除但是重復(fù)的)

      for p in permissions:
      users = set()
      for g in p.groups:
      for u in g.users:
      users.add(u)
      print ‘Permission %s has %d users’ % (p.permission_name, len(users))

      在SQLAlchemy可以這樣:

      q=select([Permission.c.permission_name,
      func.count(user_group.c.user_id)],
      and_(Permission.c.id==group_permission.c.permission_id,
      Group.c.id==group_permission.c.group_id,
      Group.c.id==user_group.c.group_id),
      group_by=[Permission.c.permission_name],
      distinct=True)
      rs=q.execute()
      for permission_name, num_users in q.execute():
      print ‘Permission %s has %d users’ % (permission_name, num_users) #雖然也長,但是減少了數(shù)據(jù)庫查詢次數(shù),也就是讓簡單事情簡單化,復(fù)雜事情可能簡單解決

      看一個綜合的例子:

      class User(object):  #這些類設(shè)計數(shù)據(jù)庫的模型

      def __init__(self, group_name=None, users=None, permissions=None):
      if users is None: users = []
      if permissions is None: permissions = []
      self.group_name = group_name
      self._users = users
      self._permissions = permissions

      def add_user(self, user):
      self._users.append(user)

      def del_user(self, user):
      self._users.remove(user)

      def add_permission(self, permission):
      self._permissions.append(permission)

      def del_permission(self, permission):
      self._permissions.remove(permission)

      class Permission(object):

      def __init__(self, permission_name=None, groups=None):
      self.permission_name = permission_name
      self._groups = groups

      def join_group(self, group):
      self._groups.append(group)

      def leave_group(self, group):
      self._groups.remove(group)

      用sqlalchemy的效果是這樣的:

      user_table = Table(
      ‘tf_user’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘user_name’, Unicode(16), unique=True, nullable=False),
      Column(‘password’, Unicode(40), nullable=False))

      group_table = Table(
      ‘tf_group’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘group_name’, Unicode(16), unique=True, nullable=False))

      permission_table = Table(
      ‘tf_permission’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘permission_name’, Unicode(16), unique=True,
      nullable=False))

      user_group = Table(
      ‘user_group’,  metadata,
      Column(‘user_id’, None, ForeignKey(‘tf_user.id’),
      primary_key=True),
      Column(‘group_id’, None, ForeignKey(‘tf_group.id’),
      primary_key=True))

      group_permission = Table(
      ‘group_permission’,  metadata,
      Column(‘group_id’, None, ForeignKey(‘tf_group.id’),
      primary_key=True),
      Column(‘permission_id’, None, ForeignKey(‘tf_permission.id’),
      primary_key=True))

      mapper(User, user_table, properties=dict(
      _groups=relation(Group, secondary=user_group, backref=’_users’)))
      mapper(Group, group_table, properties=dict(
      _permissions=relation(Permission, secondary=group_permission,
      backref=_’groups’)))
      mapper(Permission, permission_table)

      這里沒有修改對象,而join_group,leave_group這樣的函數(shù)依然可用,sqlalchemy會跟蹤變化,并且自動刷新數(shù)據(jù)庫

      上面介紹了一個完整的例子,連接數(shù)據(jù)庫嗨可以這樣:

      engine = create_engine(‘sqlite://’)
      connection = engine.connect()  #使用connect
      result = connection.execute(“select user_name from tf_user”)
      for row in result:
      print ‘user name: %s’ % row['user_name']
      result.close()

      engine = create_engine(‘sqlite://’, strategy=’threadlocal’) #,strategy=’threadlocal’表示重用其它本地線程減少對數(shù)據(jù)庫的訪問

      from sqlalchemy.databases.mysql import MSEnum, MSBigInteger  #這個 sqlalchemy.databases是某數(shù)據(jù)庫軟件的’方言’集合,只支持特定平臺
      user_table = Table(‘tf_user’, meta,
      Column(‘id’, MSBigInteger),
      Column(‘honorific’, MSEnum(‘Mr’, ‘Mrs’, ‘Ms’, ‘Miss’, ‘Dr’, ‘Prof’)))

      以下是幾個MetaData的應(yīng)用:
      unbound_meta = MetaData()  #這個metadata沒有綁定
      db1 = create_engine(‘sqlite://’)
      unbound_meta.bind = db1  #關(guān)聯(lián)引擎

      db2 = MetaData(‘sqlite:///test1.db’)  #直接設(shè)置引擎
      bound_meta1 = MetaData(db2)

      # Create a bound MetaData with an implicitly created engine
      bound_meta2 = MetaData(‘sqlite:///test2.db’)  #隱式綁定引擎
      meta = MetaData(‘sqlite://’) #直接綁定引擎可以讓源數(shù)據(jù)直接訪問數(shù)據(jù)庫

      user_table = Table(
      ‘tf_user’, meta,
      Column(‘id’, Integer, primary_key=True),
      Column(‘user_name’, Unicode(16), unique=True, nullable=False),
      Column(‘password’, Unicode(40), nullable=False))

      group_table = Table(
      ‘tf_group’, meta,
      Column(‘id’, Integer, primary_key=True),
      Column(‘group_name’, Unicode(16), unique=True, nullable=False))

      meta.create_all() #創(chuàng)建所有的數(shù)據(jù)庫(以上2個),函數(shù)無參數(shù)

      result_set = group_table.select().execute() #選取 group_table的所有表數(shù)據(jù)

      以下看一個關(guān)聯(lián)多引擎的例子:

      meta = MetaData()  #這里不能直接關(guān)聯(lián)了
      engine1 = create_engine(‘sqlite:///test1.db’)  #2個引擎
      engine2 = create_engine(‘sqlite:///test2.db’)

      # Use the engine parameter to load tables from the first engineuser_table= Table(
      ‘tf_user’, meta, autoload=True, autoload_with=engine1)  #從第一個引擎加載這些表
      group_table = Table(
      ‘tf_group’, meta, autoload=True, autoload_with=engine1)
      permission_table = Table(
      ‘tf_permission’, meta, autoload=True, autoload_with=engine1)
      user_group_table = Table(
      ‘user_group’, meta, autoload=True, autoload_with=engine1)
      group_permission_table = Table(
      ‘group_permission’, meta, autoload=True, autoload_with=engine1)

      meta.create_all(engine2) #在第二個引擎里面創(chuàng)建表

      class ImageType(sqlalchemy.types.Binary):  #自定義我們的table的類
      def convert_bind_param(self, value, engine):
      sfp = StringIO()
      value.save(sfp, ‘JPEG’)
      return sfp.getvalue()
      def convert_result_value(self, value, engine):
      sfp = StringIO(value)
      image = PIL.Image.open(sfp)
      return image  #這里我們定義了一個圖形處理的類型

      當(dāng)定義了metadata后,會自定生成一個table.cobject:
      q = user_table.select(  #查詢創(chuàng)建在2007年6月1號之前的用戶,并且第一個字母是’r’
      user_table.c.user_name.like(‘r%’)  #這里的c就是那個特殊的類,當(dāng)使用sql表達式會用到
      & user_table.c.created < datetime(2007,6,1))
      或者替代這樣:
      q = user_table.select(and_(
      user_table.c.user_name.like(‘r%’),
      user_table.c.created < datetime(2007,6,1)))
      也可以使用rom映射:
      q = session.query(User)
      q = q.filter(User.c.user_name.like(‘r%’)
      & User.c.created > datetime(2007,6,1))

      還是一個ORM的例子:

      user_table = Table(
      ‘tf_user’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘user_name’, Unicode(16), unique=True, nullable=False),
      Column(‘email_address’, Unicode(255), unique=True, nullable=False),
      Column(‘password’, Unicode(40), nullable=False),
      Column(‘first_name’, Unicode(255), default=”),
      Column(‘last_name’, Unicode(255), default=”),
      Column(‘created’, DateTime, default=datetime.now))  #這是一個定義的表類型

      group_table = Table(
      ‘tf_group’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘group_name’, Unicode(16), unique=True, nullable=False))

      user_group = Table(
      ‘user_group’,  metadata,
      Column(‘user_id’, None, ForeignKey(‘tf_user.id’), primary_key=True),
      Column(‘group_id’, None, ForeignKey(‘tf_group.id’),
      … primary_key=True))

      import sha
      class User(object):  #映射類

      def _get_password(self):
      return self._password
      def _set_password(self, value):
      self._password = sha.new(value).hexdigest() #只存儲用戶的哈希密碼
      password=property(_get_password, _set_password)

      def password_matches(self, password):
      return sha.new(password).hexdigest() == self._password

      mapper(User, user_table, properties=dict( #映射將創(chuàng)建id, user_name, email_address, password, first_name, last_name,created等字段
      _password=user_table.c.password)) #使用哈希后的密碼替換真實密碼,數(shù)據(jù)庫只保存哈希后的,這里在orm上修改

      mapper(User, user_table, properties=dict(
      _password=user_table.c.password,
      groups=relation(Group, secondary=user_group, backref=’users’))) #這里表示可以訪問所有的組,用戶只需訪問一個成員團體屬性,user_group映射類添加group和Group關(guān)聯(lián),

      # User類添加users訪問group屬性,看效果:
      group1.users.append(user1)  #給group1添加用戶user1,自動更新
      user2.groups.append(group2) #把user2添加到group2組,自動更新

      對于SQLAlchemy的一些總結(jié):

      1 metadata.create_all()

      創(chuàng)建多個table可以這樣使用,但是他還有個功能,它添加了”IF NOT EXISTS”,就是在數(shù)據(jù)庫存在的時候,他還是安全的

      2 交互模式下的一個全過程:

      Source code

         

      dongwm@localhost ~ $ python

      Python 2.7.3 (default, Jul 11 2012, 10:10:17)

      [GCC 4.5.3] on linux2

      Type "help", "copyright", "credits" or"license" for more information.

      >>> from sqlalchemy import create_engine

      >>> from sqlalchemy import Table, MetaData, Column, ForeignKey,Integer, String, Unicode, DateTime

      >>> from datetime import datetime

      >>> metadata = MetaData('sqlite:///tutorial.db')

      >>> user_table = Table(

      ...     'tf_user', metadata,

      ...     Column('id', Integer,primary_key=True),

      ...     Column('user_name',Unicode(16),

      ...            unique=True,nullable=False),

      ...     Column('password',Unicode(40), nullable=False),

      ...     Column('display_name',Unicode(255), default=''),

      ...     Column('created', DateTime,default=datetime.now))

      __main__:7: SAWarning: Unicode column received non-unicode default value.

      >>> stmt = user_table.insert() #插入數(shù)據(jù)

      >>> stmt.execute(user_name='dongwm1',password='secret',display_name='testdongwm1')

      /usr/lib/python2.7/site-packages/SQLAlchemy-0.7.8-py2.7-linux-i686.egg/sqlalchemy/engine/default.py:463:SAWarning: Unicode type received non-unicode bind param value.

       param.append(processors[key](compiled_params[key]))

      <sqlalchemy.engine.base.ResultProxy object at 0x8377fcc>

      >>> stmt.execute(user_name='dongwm2',password='secret',display_name='testdongwm2') #這個實例可以多次插入,和sql區(qū)別很大

      <sqlalchemy.engine.base.ResultProxy object at 0x837e4ec>

      >>> stmt = user_table.select() #select查詢

      >>> result = stmt.execute()

      >>> for row in result:

      ...     print row

      ...

      (1, u'dongwm1', u'secret', u'testdongwm1', datetime.datetime(2012, 7, 17,11, 57, 48, 515953))

      (2, u'dongwm2', u'secret', u'testdongwm2', datetime.datetime(2012, 7, 17,11, 58, 5, 226977))

      >>> result = stmt.execute()

      >>> row =result.fetchone() #只獲取符合要求的第一項

      >>> print  row['user_name']

      dongwm1

      >>> print row.password

      secret

      >>> print row.items()

      [(u'id', 1), (u'user_name', u'dongwm1'), (u'password', u'secret'),(u'display_name', u'testdongwm1'), (u'created', datetime.datetime(2012, 7, 17,11, 57, 48, 515953))]

      >>> stmt = user_table.select(user_table.c.user_name=='dongwm1') #過濾留下user_name=='dongwm1的項

      >>> print stmt.execute().fetchall() #獲取所有符合項

      [(1, u'dongwm1', u'secret', u'testdongwm1', datetime.datetime(2012, 7, 17,11, 57, 48, 515953))]

      >>> stmt = user_table.update(user_table.c.user_name=='dongwm1') #更新數(shù)據(jù)

      >>> stmt.execute(password='secret123') #修改密碼

      <sqlalchemy.engine.base.ResultProxy object at 0x8377f6c>

      >>> stmt = user_table.delete(user_table.c.user_name !='dongwm1')  #刪除user_name不是dongwm1的條目

      >>> stmt.execute()

      <sqlalchemy.engine.base.ResultProxy object at 0x837f3ac>

      >>> user_table.select().execute().fetchall() #查詢發(fā)現(xiàn)就剩一條了

      [(1, u'dongwm1', u'secret123', u'testdongwm1', datetime.datetime(2012, 7,17, 11, 57, 48, 515953))]

      3 sission上面已經(jīng)說過了,補充一些:

      session.delete(u) #把映射類從會話中刪除

      4 關(guān)于引擎

      引擎就是根據(jù)不同的數(shù)據(jù)庫方言連接數(shù)據(jù)庫的方法

      以下是一些例子(方法 driver://username:password@host:port/database):
      engine = create_engine(‘sqlite://’)  #連接基于內(nèi)存的sqlite
      engine = create_engine(‘sqlite:///data.sqlite’)  #連接基于硬盤文件的sqlite
      engine = create_engine(‘postgres://dongwm:foo@localhost:5432/pg_db’)  #連接postgresql
      engine = create_engine(‘mysql://localhost/mysql_db’)  #連接mysql
      engine = create_engine(‘oracle://dongwm:foo@oracle_tns’) #連接基于TNS協(xié)議的Oracle
      engine =create_engine(‘oracle://dongwm:foo@localhost:1521/oracle_sid’) #連接沒有TNS名字的Oracle

      也可以帶一些參數(shù):

      url=’postgres://dongwm:foo@localhost/pg_db?arg1=foo&arg2=bar’
      engine = create_engine(url)

      或者:

      engine = create_engine(‘postgres://dongwm:foo@localhost/pg_db’,
      connect_args=dict(arg1=’foo’, arg2=’bar’))

      還可以通過函數(shù)完全控制連接:

      import psycopg
      def connect_pg():
      return psycopg.connect(user=’rick’, host=’localhost’)
      engine = create_engine(‘postgres://’, creator=connect_pg)

      import logging
      handler = logging.FileHandler(‘sqlalchemy.engine.log’)  #可以給它添加一個日志文件處理類
      handler.level = logging.DEBUG
      logging.getLogger(‘sqlalchemy.engine’).addHandler(handler)

      上面說的操作表,也可以直接操作數(shù)據(jù)庫:

      conn = engine.connect()
      result = conn.execute(‘select user_name, email_address from tf_user’) #結(jié)果是一個sqlalchemy.engine.ResultProxy的實例
      for row in result:
      print ‘User name: %s Email address: %s’ % (
      row['user_name'], row['email_address'])
      conn.close()

      from sqlalchemy import pool #本來它已經(jīng)自動通過數(shù)據(jù)庫連接管理數(shù)據(jù)池,但是也可以手動管理
      import psycopg2
      psycopg = pool.manage(psycopg2) #結(jié)果是一個sqlalchemy.pool.DBProxy實例
      connection = psycopg.connect(database=’mydb’,
      username=’rick’, password=’foo’)

      5 關(guān)于元數(shù)據(jù)metadata

      它收集了描述table對象等的元數(shù)據(jù)類,當(dāng)使用ORM等時必須使用metadata

      如果他被綁定了,那么使用table.create()就會生成表,沒有綁定需要:table.create(bind=some_engine_or_connection),其中table.create

      包含一些函數(shù):

      autoload:默認是false,當(dāng)數(shù)據(jù)庫已經(jīng)存在這個table會自動加載覆蓋

      autoload_with:默認是false,是否自動加載引擎的字段結(jié)構(gòu)

      reflect:默認是false,是否體現(xiàn)源表結(jié)構(gòu)

      brand_table = Table(‘brand’, metadata,
      Column(‘name’, Unicode(255)), # 覆蓋類型
      autoload=True)

      6 關(guān)于表結(jié)構(gòu):

      設(shè)置表主鍵可以這樣:

      Column(‘brand_id’, Integer, ForeignKey(‘brand.id’),primary_key=True), #通過primary_key=True
      Column(‘sku’, Unicode(80), primary_key=True))
      也可以這樣:
      product_table = Table(
      ‘product’, metadata,
      Column(‘brand_id’, Integer, ForeignKey(‘brand.id’)),
      Column(‘sku’, Unicode(80)),
      PrimaryKeyConstraint(‘brand_id’, ‘sku’, name=’prikey’))  #通過PrimaryKeyConstraint

      style_table = Table(
      ‘style’, metadata,
      Column(‘brand_id’, Integer, primary_key=True),
      Column(‘sku’, Unicode(80), primary_key=True),
      Column(‘code’, Unicode(80), primary_key=True),
      ForeignKeyConstraint(  #使用復(fù)合鍵,關(guān)聯(lián)外部表的字段
      ['brand_id', 'sku'],
      ['product.brand_id', 'product.sku']))

      product_table = Table(
      ‘product’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘brand_id’, Integer, ForeignKey(‘brand.id’)), #他的brand_id關(guān)聯(lián)brand的讓id
      Column(‘sku’, Unicode(80)),
      UniqueConstraint(‘brand_id’, ‘sku’)) #約束唯一標(biāo)識數(shù)據(jù)庫表中的每條記錄

      payment_table = Table(
      ‘payment’, metadata,
      Column(‘a(chǎn)mount’, Numeric(10,2), CheckConstraint(‘a(chǎn)mount > 0′))) #驗證amount大于0
      user_table = Table(
      ‘tf_user’, MetaData(),
      Column(‘id’, Integer, primary_key=True),
      Column(‘user_name’, Unicode(16), unique=True, nullable=False),
      Column(‘password’, Unicode(40), nullable=False),
      Column(‘first_name’, Unicode(255), default=”),
      Column(‘last_name’, Unicode(255), default=”),
      Column(‘created_apptime’, DateTime, default=datetime.now), #default表示當(dāng)不舍定具體值時設(shè)定一個默認值
      Column(‘created_dbtime’, DateTime, PassiveDefault(‘sysdate’)), # PassiveDefault是數(shù)據(jù)庫級別的默認值,
      Column(‘modified’, DateTime, onupdate=datetime.now)) #單設(shè)置onupdate這個屬性,這是不應(yīng)用到數(shù)據(jù)庫的設(shè)計中的.只是存在于映射類中.

      #它是活躍更新的,因為每次執(zhí)行的時間都不同

      user_table = Table(
      ‘tf_user’, MetaData(),
      Column(‘id’, Integer, primary_key=True),
      Column(‘user_name’, Unicode(16), unique=True, nullable=False, index=True), #一旦數(shù)據(jù)庫增長到一定規(guī)模時,可能需要考慮增加表的索引,以加快某些操作
      Column(‘password’, Unicode(40), nullable=False),
      Column(‘first_name’, Unicode(255), default=”),
      Column(‘last_name’, Unicode(255), default=”, index=True))

      其中指定索引也可以這樣:

      i = Index(‘idx_name’,user_table.c.first_name,user_table.c.last_name,unique=True)
      i.create(bind=e)

      brand_table = Table(
      ‘brand’, metadata,
      Column(‘id’, Integer, Sequence(‘brand_id_seq’), primary_key=True),  #需要通過序列化方式來創(chuàng)建新主鍵標(biāo)識符的數(shù)據(jù)庫,

      #SQLAlchemy 并不會自動為其生成??梢灾付⊿equence生成
      Column(‘name’, Unicode(255), unique=True, nullable=False))

      7 元數(shù)據(jù)操作

      meta1 = MetaData(‘postgres://postgres:password@localhost/test’,
      … reflect=True)
      meta2 = MetaData(‘sqlite://’)
      for table in meta1.table_iterator():
      table.tometadata(meta2) #通過這個方法讓meta1的元數(shù)據(jù)被meta2使用
      meta2.create_all()

      2 假如想放棄綁定使用drop_all( )或者drop(e)

      1 自定義表結(jié)構(gòu)類型:

      from sqlalchemy import types

      class MyCustomEnum(types.TypeDecorator):  #自定義的類型繼承至types.TypeDecorator

      impl=types.Integer  #實現(xiàn)指定的類型int

      def __init__(self, enum_values, *l, **kw):
      types.TypeDecorator.__init__(self, *l, **kw)
      self._enum_values = enum_values

      def convert_bind_param(self, value, engine):  #必須含有這個方法,轉(zhuǎn)換python語言為SQL
      result = self.impl.convert_bind_param(value, engine)
      if result not in self._enum_values:
      raise TypeError, (
      “Value %s must be one of %s” % (result, self._enum_values))
      return result

      def convert_result_value(self, value, engine):  #必須含有這個方法,通過db的api把SQL轉(zhuǎn)換成python語言
      ‘Do nothing here’
      return self.impl.convert_result_value(value, engine)

      看一個例子:

      Source code

         

      from sqlalchemy import types

      from sqlalchemy.databases import sqlite

      class MyCustomEnum(types.TypeDecorator):

          impl = types.Integer

          def __init__(self, enum_values,*l, **kw):

             types.TypeDecorator.__init__(self, *l, **kw)

              self._enum_values =enum_values

          def bind_processor(self,dialect): #如果提供這個方法會替代convert_bind_param( )和convert_result_value( )

              impl_processor =self.impl.bind_processor(dialect)

              if impl_processor:

                  def processor(value):

                      result =impl_processor(value)

                      assert value inself._enum_values, \

                          "Value %smust be one of %s" % (result,

                         self._enum_values)

                      return result

              else:

                  def processor(value):

                      assert value inself._enum_values, \

                          "Value %smust be one of %s" % (value,

                           self._enum_values)

                      return value

              return processor

      mce=MyCustomEnum([1,2,3])

      processor = mce.bind_processor(sqlite.dialect())

      print processor(1) #返回1

      print processor(5) #返回錯誤,因為不是1,2,3中的數(shù)據(jù)


      你甚至可以直接定義自定的TypeDecorator

      class NewType(types.TypeEngine): #TypeDecorator繼承自types.TypeEngine

      def __init__(self, *args):
      self._args = args

      def get_col_spec(self):  #create_table( )會用到這個方法
      return ‘NEWTYPE(%s)’ % ‘,’.join(self._args)

      def convert_bind_param(self, value, engine):  #這個必須設(shè)置
      return value

      def convert_result_value(self, value, engine):  #這個也必須設(shè)置
      return value

      2 SQL語句在交互模式下的例子:

      dongwm@localhost ~ $ python
      Python 2.7.3 (default, Jul 11 2012, 10:10:17)
      [GCC 4.5.3] on linux2
      Type “help”, “copyright”, “credits” or “l(fā)icense” for more information.
      >>> from sqlalchemy import Table, MetaData, Column, ForeignKey,Integer, String, Unicode, DateTime
      >>> metadata=MetaData()
      >>> simple_table = Table(  #一個簡單的表結(jié)構(gòu)
      …     ‘simple’, metadata,
      …     Column(‘id’, Integer, primary_key=True),
      …     Column(‘col1′, Unicode(20)))
      >>>
      >>> stmt = simple_table.insert()  #插入數(shù)據(jù)操作的實例
      >>> print stmt #打印這個實例
      INSERT INTO simple (id, col1) VALUES (:id, :col1) #里面包含需要替換的變量
      >>> compiled_stmt = stmt.compile()  #編譯語句
      >>> print compiled_stmt.params #轉(zhuǎn)成了字典得方式
      {‘id’: None, ‘col1′: None}
      >>> from sqlalchemy import create_engine
      >>> engine = create_engine(‘sqlite://’)
      >>> simple_table.create(bind=engine)  #創(chuàng)建table
      >>> engine.execute(stmt, col1=”Foo”) #給語句添加值
      /usr/lib/python2.7/site-packages/SQLAlchemy-0.7.8-py2.7-linux-i686.egg/sqlalchemy/engine/default.py:463:SAWarning: Unicode type received non-unicode bind param value.
      param.append(processors[key](compiled_params[key]))
      <sqlalchemy.engine.base.ResultProxy object at 0x8376c8c>
      >>> metadata.bind = engine  #和上面效果一樣,給語句添加值
      >>> stmt.execute(col1=”Bar”)
      <sqlalchemy.engine.base.ResultProxy object at 0x8376f4c>
      >>> stmt = simple_table.insert(values=dict(col1=”Initial value”)) #這次插入已經(jīng)設(shè)置了值
      >>> print stmt
      INSERT INTO simple (col1) VALUES (?)
      >>> compiled_stmt = stmt.compile()
      >>> print compiled_stmt.params
      {‘col1′: ‘Initial value’}
      >>> stmt = simple_table.insert()
      >>> stmt.execute(col1=”First value”)
      <sqlalchemy.engine.base.ResultProxy object at 0x838832c>
      >>>
      >>> stmt.execute(col1=”Second value”)
      <sqlalchemy.engine.base.ResultProxy object at 0x838844c>
      >>> stmt.execute(col1=”Third value”) #這樣一行一行插入真是費勁
      <sqlalchemy.engine.base.ResultProxy object at 0x838856c>
      >>> stmt.execute([dict(col1="Fourth Value"), #可以一次插入多行
      ...     dict(col1="Fifth Value"),
      ...     dict(col1="Sixth Value")])
      <sqlalchemy.engine.base.ResultProxy object at 0x83886ac>
      >>> from sqlalchemy import text
      >>> stmt = simple_table.update(
      …     whereclause=text(“col1=’First value’”),
      …     values=dict(col1=’1st Value’))  #執(zhí)行col1是First value的條目設(shè)置值為1st Value
      >>> stmt.execute()
      <sqlalchemy.engine.base.ResultProxy object at 0x838878c>
      >>> stmt = simple_table.update(text(“col1=’Second value’”)) #尋找col1是Second value的條目
      >>> stmt.execute(col1=’2nd Value’) #執(zhí)行更新時,設(shè)置其值,想過和上面的一樣
      <sqlalchemy.engine.base.ResultProxy object at 0x8376f4c>
      >>> stmt = simple_table.update(text(“col1=’Third value’”))
      >>> print stmt
      UPDATE simple SET id=?, col1=? WHERE col1=’Third value’
      >>> engine.echo = True #設(shè)置打印調(diào)試日志
      >>> stmt.execute(col1=’3rd value’)
      2012-07-17 15:16:59,231 INFO sqlalchemy.engine.base.Engine UPDATE simple SETcol1=? WHERE col1=’Third value’
      2012-07-17 15:16:59,245 INFO sqlalchemy.engine.base.Engine (’3rd value’,)
      2012-07-17 15:16:59,245 INFO sqlalchemy.engine.base.Engine COMMIT
      <sqlalchemy.engine.base.ResultProxy object at 0x83767ec>

      >>> stmt = simple_table.delete(  #刪除
      …     text(“col1=’Second value’”))
      >>> stmt.execute()
      2012-07-17 15:21:03,806 INFO sqlalchemy.engine.base.Engine DELETE FROM simpleWHERE col1=’Second value’
      2012-07-17 15:21:03,806 INFO sqlalchemy.engine.base.Engine ()
      2012-07-17 15:21:03,806 INFO sqlalchemy.engine.base.Engine COMMIT
      <sqlalchemy.engine.base.ResultProxy object at 0x8376a0c>
      >>> from sqlalchemy import select
      >>> stmt = select([simple_table.c.col1])  #查詢col1這個字段
      >>> for row in stmt.execute():
      …     print row
      (u’Foo’,)
      (u’Bar’,)
      (u’1st Value’,)
      (u’2nd Value’,)
      (u’3rd value’,)
      (u’Fourth Value’,)
      (u’Fifth Value’,)
      (u’Sixth Value’,)

      >>> stmt = simple_table.select() #和上面的區(qū)別是這是條目全部顯示
      >>> for row in stmt.execute():  #這2句也可以這樣表示stmt = select( simple_table])
      …     print row

      (1, u’Foo’)
      (2, u’Bar’)
      (3, u’1st Value’)
      (4, u’2nd Value’)
      (5, u’3rd value’)
      (6, u’Fourth Value’)
      (7, u’Fifth Value’)
      (8, u’Sixth Value’)
      >>> x = simple_table.c.col1==”Foo”
      >>> print type(x)
      <class ‘sqlalchemy.sql.expression._BinaryExpression’>
      >>> print x
      simple.col1 = :col1_1
      >>> expr = simple_table.c.col1 + “-col1″  #它還支持運算符
      >>> print expr
      simple.col1 || :col1_1
      >>> from sqlalchemy.databases import mysql
      >>> print expr.compile(dialect=mysql.MySQLDialect())
      concat(simple.col1, %s) #在不同的數(shù)據(jù)庫軟件,效果不同

      >>> from sqlalchemy import func
      >>> print func.now()
      now()
      >>> print func.current_timestamp
      <sqlalchemy.sql.expression._FunctionGenerator object at 0x83888cc>
      >>> print func._(text(‘a(chǎn)=b’))
      (a=b)

      注:sqlalchemy支持in,op,startwith,endwith,between,like等運算

      >>> from sqlalchemy import bindparam  #自定義綁定的詞
      >>> stmt = select([simple_table.c.col1],
      …    whereclause=simple_table.c.col1==bindparam(‘test’))  #用test替換原來的col1
      >>> print stmt
      SELECT simple.col1
      FROM simple
      WHERE simple.col1 = ? #這里依然是col1
      >>> print stmt.execute(test=’Foo’).fetchall()
      [(u'Foo',)]

      >>> stmt =simple_table.select(order_by=[simple_table.c.col1])  #更具col1,升序排序
      >>> print stmt
      SELECT simple.id, simple.col1
      FROM simple ORDER BY simple.col1
      >>> print stmt.execute().fetchall()
      [(3, u'1st Value'), (4, u'2nd Value'), (5, u'3rd value'), (2, u'Bar'), (7,u'Fifth Value'), (1, u'Foo'), (6, u'Fourth Value'), (8, u'Sixth Value')]
      >>> from sqlalchemy import desc
      >>> stmt = simple_table.select(order_by=[desc(simple_table.c.col1)]) #根據(jù)col1,降序排序
      >>> print stmt
      SELECT simple.id, simple.col1
      FROM simple ORDER BY simple.col1 DESC
      >>> print stmt.execute().fetchall()
      [(8, u'Sixth Value'), (6, u'Fourth Value'), (1, u'Foo'), (7, u'Fifth Value'),(2, u'Bar'), (5, u'3rd value'), (4, u'2nd Value'), (3, u'1st Value')]
      注:distinct=True去重復(fù),效果類似于SELECT DISTINCT

      >>> stmt = simple_table.select(offset=1, limit=1) #offset設(shè)置偏移,這里就是略過第一個,返回第二個.limit設(shè)置返回多少個條目
      >>> print stmt
      SELECT simple.id, simple.col1
      FROM simple
      LIMIT ? OFFSET ?
      >>> print stmt.execute().fetchall()
      [(2, u'Bar')]
      看下面的例子:

      “Persons” 表:

      Id_P

      LastName

      FirstName

      Address

      City

      1

      Adams

      John

      Oxford Street

      London

      2

      Bush

      George

      Fifth Avenue

      New York

      3

      Carter

      Thomas

      Changan Street

      Beijing

      “Orders” 表:

      Id_O

      OrderNo

      Id_P

      1

      77895

      3

      2

      44678

      3

      3

      22456

      1

      4

      24562

      1

      5

      34764

      65

      現(xiàn)在,我們希望列出所有的人,以及他們的定購號碼:

      SELECT Persons.LastName, Persons.FirstName,Orders.OrderNo

      FROM Persons

      LEFT JOIN Orders #將orders表join進來

      ON Persons.Id_P=Orders.Id_P #關(guān)系聯(lián)系

      ORDER BY Persons.LastName #排序

      書中的例子是這樣的:

      SELECT store.name

      FROM store

      JOIN product_price ON store.id=product_price.store_id

      JOIN product ON product_price.sku=product.sku

      WHERE product.msrp != product_price.price;

      轉(zhuǎn)換成sqlalchemy語句:

      >>>from_obj =store_table.join(product_price_table).join(product_table)

      >>> query = store_table.select()

      >>> query = query.select_from(from_obj)

      >>> query = query.where(product_table.c.msrp !=product_price_table.c.price)

      >>> print query

      SELECT store.id, store.name

      FROM store JOIN product_price ON store.id =product_price.store_id JOIN product ON product.sku = product_price.sku

      WHERE product.msrp != product_price.price

      >>> print query.column(‘product.sku’)
      SELECT store.id, store.name, product.sku
      FROM store JOIN product_price ON store.id = product_price.store_id  JOINproduct ON product.sku = product_price.sku
      WHERE product.msrp != product_price.price
      >>> query2 = select([store_table,product_table.c.sku],from_obj=[from_obj],whereclause=(product_table.c.msrp!=product_price_table.c.price))
      >>> print query2
      SELECT store.id, store.name, product.sku
      FROM store JOIN product_price ON store.id = product_price.store_id JOIN productON product.sku = product_price.sku
      WHERE product.msrp != product_price.price
      >>> query = product_table.select(and_(product_table.c.msrp > 10.00,product_table.c.msrp < 20.00)) #范圍查詢
      >>> print query
      SELECT product.sku, product.msrp
      FROM product
      WHERE product.msrp > ? AND product.msrp < ?
      >>> for r in query.execute():
      …print r
      (u’123′, Decimal(“12.34″))

      >>> from sqlalchemy import intersect

      >>> query0 = product_table.select(product_table.c.msrp >10.00)
      >>> query1 = product_table.select(product_table.c.msrp < 20.00)
      >>> query = intersect(query0, query1) #使用 intersect添加多query
      >>> print query
      SELECT product.sku, product.msrp

      employee_table = Table(
      ‘employee’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘manager’, None, ForeignKey(‘employee.id’)),
      Column(‘name’, String(255)))

      給設(shè)定alias:

      比如想實現(xiàn)以下SQL

      SELECT employee.name
      FROM employee, employee AS manager
      WHERE employee.manager_id = manager.id
      AND manager.name = ‘Fred’

      >>> manager = employee_table.alias(‘mgr’)
      >>> stmt = select([employee_table.c.name],

      and_(employee_table.c.manager_id==manager.c.id,

      manager.c.name==’Fred’))
      >>> print stmt
      SELECT employee.name
      FROM employee, employee AS mgr
      WHERE employee.manager_id = mgr.id AND mgr.name = ?

      >>> manager = employee_table.alias()  #自動alias
      >>> stmt = select([employee_table.c.name],
      …and_(employee_table.c.manager_id==manager.c.id,
      …manager.c.name==’Fred’))
      >>> print stmt
      SELECT employee.name
      FROM employee, employee AS employee_1
      WHERE employee.manager_id = employee_1.id AND employee_1.name = ?

       

       

      from sqlalchemy import types
      class MyCustomEnum(types.TypeDecorator):
      impl=types.Integer
      def __init__(self, enum_values, *l, **kw):
      types.TypeDecorator.__init__(self, *l, **kw)
      self._enum_values = enum_values
      def convert_bind_param(self, value, engine):
      result = self.impl.convert_bind_param(value, engine)
      if result not in self._enum_values:
      raise TypeError, (
      “Value %s must be one of %s” % (result, self._enum_values))
      Application-Specific Custom Types | 63return result
      def convert_result_value(self, value, engine):
      ‘Do nothing here’
      return self.impl.convert_result_value(value, engine)

      1  ORM模型的簡單性簡化了數(shù)據(jù)庫查詢過程。使用ORM查詢工具,用戶可以訪問期望數(shù)據(jù),而不必理解數(shù)據(jù)庫的底層結(jié)構(gòu)

      以下是SQL語句:
      region_table = Table(
      ‘region’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘name’, Unicode(255)))
      相應(yīng)的類:
      class Region(object):

      def __init__(self, name):
      self.name = name

      def __repr__(self):
      return ‘<Region %s>’ % self.name

      看一下在交互模式下:

      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__']
      >>> mapper(Region,region_table)  #ORM映射
      <Mapper at 0x84bdb2c; Region>
      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__', '_sa_class_manager', 'id','name'] #增加了很多屬性
      >>> Region.id
      <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x84c238c>
      >>> Region.name
      <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x84c254c>

      >>> r0 = Region(name=”Northeast”)
      >>> r1 = Region(name=”Southwest”)
      >>> r0
      <Region Northeast>  #類能顯示這樣的數(shù)據(jù)是因為類定義了__repr__方法
      >>> r1
      <Region Southwest>
      >>> from sqlalchemy.orm import clear_mappers
      >>> clear_mappers() #取消映射
      >>> Region.name #不再有這個屬性
      Traceback (most recent call last):
      File “<stdin>”, line 1, in <module>
      AttributeError: type object ‘Region’ has no attribute ‘name’
      >>> dir(Region)  #回到了原來的只有類屬性
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__']

      >>> r0 = Region(name=”Northeast”)  #從這里開始理解ORM做了什么
      >>> r1 = Region(name=”Southwest”) #實現(xiàn)了2個類的實例

      >>> metadata.create_all(engine) #創(chuàng)建table

      >>> Session = sessionmaker()  #通過sessionmaker產(chǎn)生一個會話
      >>> Session.configure(bind=engine) #綁定到數(shù)據(jù)庫連接
      >>> session = Session()  #產(chǎn)生會話實例,讓對象可以被載入或保存到數(shù)據(jù)庫,而只需要訪問類卻不用直接訪問數(shù)據(jù)庫
      >>> session.bind.echo = True #顯示打印信息

      >>> session.add(r1) #把r0,r12個實例加到會話中
      >>> session.add(r0)
      >>> print r0.id  #因為還沒有保存,數(shù)據(jù)為空
      None
      >>> session.flush() #提交數(shù)據(jù)到數(shù)據(jù)庫
      2012-07-18 10:24:07,116 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
      2012-07-18 10:24:07,116 INFO sqlalchemy.engine.base.Engine INSERT INTO region(name) VALUES (?)
      2012-07-18 10:24:07,116 INFO sqlalchemy.engine.base.Engine (‘Southwest’,)
      2012-07-18 10:24:07,117 INFO sqlalchemy.engine.base.Engine INSERT INTO region(name) VALUES (?)
      2012-07-18 10:24:07,117 INFO sqlalchemy.engine.base.Engine (‘Northeast’,)
      >>> print r0.id #id因為子增長,出現(xiàn)了
      2
      >>> r0.name = ‘Northwest’
      >>> session.flush() #修改提交
      2012-07-18 10:24:50,644 INFO sqlalchemy.engine.base.Engine UPDATE region SETname=? WHERE region.id = ?
      2012-07-18 10:24:50,644 INFO sqlalchemy.engine.base.Engine (‘Northwest’, 2)
      >>> print r0.name #數(shù)據(jù)庫中的數(shù)據(jù)被update成了新值
      Northwest
      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__','__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__','__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__','__weakref__']
      >>> mapper(Region, region_table, include_properties=['id']) #使用 include_properties只映射某些字段,同樣還有exclude_properties
      <Mapper at 0x84c26cc; Region>
      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__', '_sa_class_manager', 'id'] #只多了一個”id”

      >>> clear_mappers()
      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__']
      >>> mapper(Region, region_table, column_prefix=’_')  #映射后自定義修改新屬性的前綴
      <Mapper at 0x84f73ac; Region>
      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__', '_id', '_name','_sa_class_manager'] #id和name等前面都有了”_”

      >>> clear_mappers()
      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__']
      >>> mapper(Region, region_table, properties=dict(
      …     region_name=region_table.c.name,  #想把name的屬性定義為region_name,因為c.name就是用Table創(chuàng)建的表結(jié)構(gòu)的特定實例的name屬性
      …     region_id=region_table.c.id))
      <Mapper at 0x8509d2c; Region>
      >>> dir(Region)
      ['__class__', '__delattr__', '__dict__', '__doc__', '__format__','__getattribute__', '__hash__', '__init__', '__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__', '__weakref__', '_sa_class_manager', 'region_id','region_name']  #id改名為region_id

      >>> class Region(object):  #重新定義類
      …     def __init__(self, name):
      …         self.name = name
      …     def __repr__(self):
      …         return ‘<Region %s>’ %self.name
      …     def _get_name(self): #這個_get和_set是為了讓內(nèi)置的property調(diào)用
      …         return self._name
      …     def _set_name(self, value):
      …         assertvalue.endswith(‘Region’), \
      …            ‘Region names must end in “Region”‘
      …         self._name = value
      …     name=property(_get_name, _set_name) #通過property的定義,當(dāng)獲取成員x的值時,就會調(diào)用_get_name函數(shù)(第一個參數(shù)),當(dāng)給成員x賦值時,就會調(diào)用_set_name函數(shù)(第二個參數(shù)),當(dāng)刪除x時,就會調(diào)用delx函數(shù)(這里沒有設(shè)置)

      >>> from sqlalchemy.orm import synonym
      >>> mapper(Region, region_table, column_prefix=’_', properties=dict(
      …     name=synonym(‘_name’))) #首先檢驗_name的屬性是否滿足
      <Mapper at 0x84f7acc; Region>
      >>> s0 = Region(‘Southeast’)  #沒有正確結(jié)尾
      Traceback (most recent call last):
      File “<stdin>”, line 1, in <module>
      File “<string>”, line 4, in __init__
      File“/usr/lib/python2.7/site-packages/SQLAlchemy-0.7.8-py2.7-linux-i686.egg/sqlalchemy/orm/state.py”,line 98, in initialize_instance
      return manager.original_init(*mixed[1:], **kwargs)
      File “<stdin>”, line 3, in __init__
      File “<string>”, line 1, in __set__
      File “<stdin>”, line 10, in _set_name
      AssertionError: Region names must end in “Region”
      >>> s0 = Region(‘Southeast Region’) #正常

      >>> segment_table = Table(
      …     ‘segment’, metadata,
      …     Column(‘id’, Integer, primary_key=True),
      …     Column(‘lat0′, Float),
      …     Column(‘long0′, Float),
      …     Column(‘lat1′, Float),
      …     Column(‘long1′, Float))

      >>> metadata.create_all(engine) #創(chuàng)建表
      >>> class RouteSegment(object): #一個含有begin和end的類
      …     def __init__(self, begin, end):
      …         self.begin = begin
      …         self.end = end
      …     def __repr__(self):
      …         return ‘<Route %s to%s>’ % (self.begin, self.end)

      >>> class MapPoint(object):
      …     def __init__(self, lat, long):
      …         self.coords = lat, long
      …     def __composite_values__(self): #返回比較后的列表或者元祖
      …         return self.coords
      …     def __eq__(self, other):
      …         return self.coords ==other.coords
      …     def __ne__(self, other):
      …         return self.coords !=other.coords
      …     def __repr__(self):
      …         return ‘(%s lat, %s long)’ %self.coords

      >>> from sqlalchemy.orm import composite
      >>> mapper(RouteSegment, segment_table, properties=dict(
      …     begin=composite(MapPoint,  #創(chuàng)建多個屬性
      …         segment_table.c.lat0,
      …         segment_table.c.long0),
      …     end=composite(MapPoint,
      …         segment_table.c.lat1,segment_table.c.long1)))
      <Mapper at 0x86203cc; RouteSegment>
      >>> work=MapPoint(33.775562,-84.29478)
      >>> library=MapPoint(34.004313,-84.452062)
      >>> park=MapPoint(33.776868,-84.389785)
      >>> routes = [
      ...     RouteSegment(work, library),
      ...     RouteSegment(work, park),
      ...     RouteSegment(library, work),
      ...     RouteSegment(library, park),
      ...     RouteSegment(park, library),
      ...     RouteSegment(park, work)]

      >>> for rs in routes:
      …     session.add(rs)

      >>> session.flush()
      >>> q = session.query(RouteSegment)
      >>> print RouteSegment.begin==work
      segment.lat0 = :lat0_1 AND segment.long0 = :long0_1
      >>> q = q.filter(RouteSegment.begin==work)
      >>> for rs in q:
      …     print rs

      2012-07-18 11:12:29,360 INFO sqlalchemy.engine.base.Engine SELECT segment.id ASsegment_id, segment.lat0 AS segment_lat0, segment.long0 AS segment_long0,segment.lat1 AS segment_lat1, segment.long1 AS segment_long1
      FROM segment
      WHERE segment.lat0 = ? AND segment.long0 = ?
      2012-07-18 11:12:29,360 INFO sqlalchemy.engine.base.Engine (33.775562,-84.29478)
      <Route (33.775562 lat, -84.29478 long) to (34.004313 lat, -84.452062long)>
      <Route (33.775562 lat, -84.29478 long) to (33.776868 lat, -84.389785long)>

      >>> from sqlalchemy.orm import PropComparator
      >>> class MapPointComparator(PropComparator): #自定義運算符繼承PropComparator類
      …     def __lt__(self, other):  #自定義小于運算結(jié)果
      …         return and_(*[a<b for a, bin
      ...            zip(self.prop.columns,
      ...                other.__composite_values__())])

      >>> mapper(RouteSegment, segment_table, properties=dict(
      …     begin=composite(MapPoint,
      …                    segment_table.c.lat0, segment_table.c.long0,
      …                    comparator=MapPointComparator),  #定義使用自定義的運算類
      …     end=composite(MapPoint,
      …                  segment_table.c.lat1, segment_table.c.long1,
      …                  comparator=MapPointComparator)))
      <Mapper at 0x85b2bac; RouteSegment>
      >>> product_table = Table(
      … ‘product’, metadata,
      … Column(‘sku’, String(20), primary_key=True),
      … Column(‘msrp’, Numeric),
      … Column(‘image’, BLOB))
      >>> from sqlalchemy.orm import deferred
      >>> mapper(Product, product_table, properties=dict(
      …     image=deferred(product_table.c.image))) #deferred意思是延遲,就是在實現(xiàn) mapper 時,可以指定某些字段是 Deferred 裝入的,這樣象通常一樣取出數(shù)據(jù)時,這些字段并不真正的從數(shù)據(jù)庫中取出,只有在你真正需要時才取出,這樣可以減少資源的占用和提高效率,只有在讀取 image時才會取出相應(yīng)的數(shù)據(jù)
      <Mapper at 0x862a40c; Product>

      >>> metadata.remove(product_table)  #因為已經(jīng)常見了表,先刪除
      >>> product_table = Table(
      …     ‘product’, metadata,
      …     Column(‘sku’, String(20), primary_key=True),
      …     Column(‘msrp’, Numeric),
      …     Column(‘image1′, Binary),
      …     Column(‘image2′, Binary),
      …     Column(‘image3′, Binary))

      >>> clear_mappers() #已經(jīng)映射,先取消
      >>> mapper(Product, product_table, properties=dict(
      …     image1=deferred(product_table.c.image1,group=’images’),
      …     image2=deferred(product_table.c.image2,group=’images’),
      …     image3=deferred(product_table.c.image3,group=’images’))) #Deferred字段可以通過在 properties 中指定 group參數(shù)來表示編組情況。這樣當(dāng)一個組的某個

      #字段被取出時, 同組的其它字段均被取出
      <Mapper at 0x85b8c4c; Product>

      >>> q = product_table.join(  被映射的是join了product_summary_table到product_table的結(jié)果
      … product_summary_table,
      … product_table.c.sku==product_summary_table.c.sku).alias(‘full_product’)
      >>> class FullProduct(object): pass

      >>> mapper(FullProduct, q)
      <Mapper at 0x86709cc; FullProduct>

      mapper函數(shù)的一些參數(shù):

      always_refresh =False:返回查詢舊會修改內(nèi)存中的值,但是populate_existing優(yōu)先級高

      allow_column_override =False:允許關(guān)系屬性將具有相同的名稱定義為一個映射列,否則名稱沖突,產(chǎn)生異常

      2 ORM的關(guān)系

      1 1:N relations (1對多)

      >>> mapper(Store, store_table)
      <Mapper at 0x84fba4c; Store>
      >>> from sqlalchemy.orm import relation
      >>> mapper(Region, region_table, properties=dict(
      …     stores=relation(Store))) #讓2個表關(guān)聯(lián),給Region添加一個屬性stores,通過它聯(lián)系Store來修改Store
      <Mapper at 0x84f76ac; Region>

      >>> r0 = Region(‘test’)

      >>> session.add(r0) #先生成一條數(shù)據(jù)
      >>> session.commit()
      2012-07-18 13:56:26,858 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
      2012-07-18 13:56:26,859 INFO sqlalchemy.engine.base.Engine INSERT INTO region(name) VALUES (?)
      2012-07-18 13:56:26,859 INFO sqlalchemy.engine.base.Engine (‘test’,)
      2012-07-18 13:56:26,859 INFO sqlalchemy.engine.base.Engine COMMIT
      >>> rgn = session.query(Region).get(1)  #獲取這條數(shù)據(jù)
      2012-07-18 13:56:37,250 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
      2012-07-18 13:56:37,251 INFO sqlalchemy.engine.base.Engine SELECT region.id ASregion_id, region.name AS region_name
      FROM region
      WHERE region.id = ?
      2012-07-18 13:56:37,251 INFO sqlalchemy.engine.base.Engine (1,)
      >>> s0 = Store(name=’3rd and Juniper’) #創(chuàng)建一個實例
      >>> rgn.stores.append(s0) #通過Region的依賴建立新的Store(其中的一個字段region_id值來著region的id字段)
      2012-07-18 13:56:51,611 INFO sqlalchemy.engine.base.Engine SELECT store.id ASstore_id, store.region_id AS store_region_id, store.name AS store_name
      FROM store
      WHERE ? = store.region_id
      2012-07-18 13:56:51,611 INFO sqlalchemy.engine.base.Engine (1,)
      >>> session.flush() #保存數(shù)據(jù)庫
      2012-07-18 13:57:02,131 INFO sqlalchemy.engine.base.Engine INSERT INTO store(region_id, name) VALUES (?, ?)
      2012-07-18 13:57:02,131 INFO sqlalchemy.engine.base.Engine (1, ’3rd andJuniper’)
      注:假如2個表之間有多個外部依賴關(guān)系,需要使用primaryjoin指定:

      mapper(Region, region_table, properties=dict(
      stores=relation(Store,
      primaryjoin=(store_table.c.region_id  #判斷關(guān)系來著region_id和region的id
      ==region_table.c.id))))

      2 M:N relations(多對多)

      上面有SQL語句:我復(fù)制過來:

      category_table = Table(
      ‘category’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘level_id’, None, ForeignKey(‘level.id’)),
      Column(‘parent_id’, None, ForeignKey(‘category.id’)),
      Column(‘name’, String(20)))
      product_table = Table(
      ‘product’, metadata,
      Column(‘sku’, String(20), primary_key=True),
      Column(‘msrp’, Numeric))
      product_category_table = Table(
      ‘product_category’, metadata,
      Column(‘product_id’, None, ForeignKey(‘product.sku’), primary_key=True),
      Column(‘category_id’, None, ForeignKey(‘category.id’), primary_key=True))

      可以看出來product_category_table和category_table 是多對多的關(guān)系.

      >>> mapper(Category, category_table, properties=dict(
      …     products=relation(Product,
      …     secondary=product_category_table)))
      <Mapper at 0x859c8cc; Category>
      >>> mapper(Product, product_table, properties=dict(
      …     categories=relation(Category,
      …     secondary=product_category_table)))
      <Mapper at 0x859c5cc; Product>

      >>> r0=Product(’123′,’234′)

      >>> session.add(r0)
      >>> session.flush()
      2012-07-18 14:18:06,599 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
      2012-07-18 14:18:06,618 INFO sqlalchemy.engine.base.Engine INSERT INTO product(sku, msrp) VALUES (?, ?)
      2012-07-18 14:18:06,618 INFO sqlalchemy.engine.base.Engine (’123′, 234.0)
      >>> session.query(Product).get(’123′).categories

      >>> clear_mappers()
      >>> mapper(Category, category_table, properties=dict(
      …     products=relation(Product,secondary=product_category_table,
      … primaryjoin=(product_category_table.c.category_id  #primaryjoin是要被映射的表和連接表的條件
      …                                   == category_table.c.id),
      … secondaryjoin=(product_category_table.c.product_id  #secondaryjoin是連接表和想加入的表的條件
      …                                     == product_table.c.sku))))
      <Mapper at 0x84ff7cc; Category>
      >>> mapper(Product, product_table, properties=dict(
      …     categories=relation(Category,secondary=product_category_table,
      … primaryjoin=(product_category_table.c.product_id
      …                                     == product_table.c.sku),
      … secondaryjoin=(product_category_table.c.category_id
      …                                       == category_table.c.id))))
      <Mapper at 0x859cb8c; Product>
      1:1 relations(一對一):特殊的(1:N)
      還是上面的SQL:

      product_table = Table(
      ‘product’, metadata,
      Column(‘sku’, String(20), primary_key=True),
      Column(‘msrp’, Numeric))
      product_summary_table = Table(
      ‘product_summary’, metadata,
      Column(‘sku’, None, ForeignKey(‘product.sku’), primary_key=True), #只有一個外聯(lián)到product
      Column(‘name’, Unicode(255)),
      Column(‘description’, Unicode))

      >>> mapper(Product, product_table, properties=dict(
      …     summary=relation(ProductSummary)))
      KeyboardInterrupt
      >>> mapper(ProductSummary, product_summary_table)
      <Mapper at 0x84fbe6c; ProductSummary>
      >>> mapper(Product, product_table, properties=dict(
      …     summary=relation(ProductSummary)))
      <Mapper at 0x85bee6c; Product>
      >>> prod = session.query(Product).get(’123′)
      []  #product_summary_table因為product_table兒存在,浪費了

      >>> mapper(ProductSummary, product_summary_table)
      <Mapper at 0x84f7dec; ProductSummary>
      >>> mapper(Product, product_table, properties=dict(
      …    summary=relation(ProductSummary,uselist=False)))  #使用uselist=False就不會這樣了
      <Mapper at 0x860584c; Product>
      >>> prod = session.query(Product).get(’123′)
      >>> print prod.summary
      None
      >>> mapper(ProductSummary, product_summary_table)
      <Mapper at 0x859ca0c; ProductSummary>
      >>> mapper(Product, product_table, properties=dict(
      …     summary=relation(ProductSummary, uselist=False,
      …     backref=’product’))) #自定義自己表的函數(shù)
      <Mapper at 0x860e90c; Product>
      >>> prod = session.query(Product).get(’123′)
      >>> prod.summary = ProductSummary(name=”Fruit”, description=”Some
      … Fruit”)
      >>> print prod.summary
      <ProductSummary Fruit>
      >>> print prod.summary.product #他的屬性就是prod,可就是表本身
      <Product 123>
      >>> print prod.summary.product is prod
      True

      >>> mapper(Level, level_table, properties=dict(
      …     categories=relation(Category, backref=’level’)))
      <Mapper at 0x860590c; Level>
      >>> mapper(Category, category_table, properties=dict(
      …     products=relation(Product,
      …        secondary=product_category_table)))
      <Mapper at 0x860ec8c; Category>
      >>> mapper(Product, product_table, properties=dict(
      …     categories=relation(Category,
      …        secondary=product_category_table)))
      <Mapper at 0x860e7ec; Product>
      >>> lvl = Level(name=’Department’)
      >>> cat = Category(name=’Produce’, level=lvl)
      >>> session.add(lvl)
      >>> session.flush()
      2012-07-18 14:44:02,005 INFO sqlalchemy.engine.base.Engine INSERT INTO level(parent_id, name) VALUES (?, ?)
      2012-07-18 14:44:02,005 INFO sqlalchemy.engine.base.Engine (None, ‘Department’)
      2012-07-18 14:44:02,020 INFO sqlalchemy.engine.base.Engine INSERT INTO category(level_id, parent_id, name) VALUES (?, ?, ?)
      2012-07-18 14:44:02,020 INFO sqlalchemy.engine.base.Engine (1, None, ‘Produce’)
      >>> prod = session.query(Product).get(’123′)
      >>> print prod.categories
      []
      >>> print cat.products
      2012-07-18 14:44:25,517 INFO sqlalchemy.engine.base.Engine SELECT product.skuAS product_sku, product.msrp AS product_msrp
      FROM product, product_category
      WHERE ? = product_category.category_id AND product.sku =product_category.product_id
      2012-07-18 14:44:25,517 INFO sqlalchemy.engine.base.Engine (1,)
      []
      >>> prod.categories.append(cat)
      >>> print prod.categories
      [<Category Department.Produce>]
      >>> print cat.products  #backref自動更新,在多對多的情況,可以使用relation函數(shù)兩次,但是2個屬性沒有保持同步
      []  #解決方法:

      >>> mapper(Level, level_table, properties=dict(
      …categories=relation(Category, backref=’level’)))
      >>> mapper(Category, category_table, properties=dict(
      …products=relation(Product, secondary=product_category_table,
      … backref=’categories’)))  #在Product也設(shè)置backref,就會保持同步
      >>> mapper(Product, product_table)
      >>> lvl = Level(name=’Department’)
      >>> cat = Category(name=’Produce’, level=lvl)
      >>> session.save(lvl)
      >>> prod = session.query(Product).get(’123′)
      >>> print prod.categories
      []
      >>> print cat.products
      []
      >>> prod.categories.append(cat)
      >>> print prod.categories
      [<Category Department.Produce>]
      >>>print cat.products
      [<Product 123>]

      >>> from sqlalchemy.orm import backref
      >>> clear_mappers()
      >>> mapper(ProductSummary, product_summary_table, properties=dict(
      … product=relation(Product,
      … backref=backref(‘summary’, uselist=False))))  #還可以使用backref函數(shù)做一樣的事情
      <Mapper at 0x860aaec; ProductSummary>
      >>> mapper(Product, product_table)
      <Mapper at 0x85bee6c; Product>

      4 Self-Referential 自我參照映射
      level_table = Table(
      ‘level’, metadata,
      Column(‘id’, Integer, primary_key=True),
      Column(‘parent_id’, None, ForeignKey(‘level.id’)), #這個外聯(lián)其實還是這個類的id,也就是映射了自己的對象
      Column(‘name’, String(20)))
      >>> mapper(Level, level_table, properties=dict(
      … children=relation(Level))) #不同層次之間的父子關(guān)系,我這里指定得到”子”的屬性
      <Mapper at 0x860a66c; Level>
      >>> mapper(Level, level_table, properties=dict(
      …     children=relation(Level,
      …     backref=backref(‘parent’,
      …     remote_side=[level_table.c.id]))))  #remote_side指定’子’的id,local side”就是字段parent_id
      <Mapper at 0x860e42c; Level>
      >>> l0 = Level(‘Gender’)
      >>> l1 = Level(‘Department’, parent=l0)
      >>> session.add(l0)
      >>> session.flush()
      2012-07-18 15:07:55,810 INFO sqlalchemy.engine.base.Engine INSERT INTO level(parent_id, name) VALUES (?, ?)
      2012-07-18 15:07:55,810 INFO sqlalchemy.engine.base.Engine (None, ‘Gender’) #插入l0,他沒有父級
      2012-07-18 15:07:55,810 INFO sqlalchemy.engine.base.Engine INSERT INTO level(parent_id, name) VALUES (?, ?)
      2012-07-18 15:07:55,810 INFO sqlalchemy.engine.base.Engine (2, ‘Department’)

      注 我們還能反過來用:

      mapper(Level, level_table, properties=dict(
      parent=relation(Level, remote_side=[level_table.c.parent_id],
      backref=’children’)))

      我們創(chuàng)建一個多引擎的例子:

      Source code

         

      from sqlalchemy import create_engine

      from sqlalchemy.orm import mapper, sessionmaker

      from sqlalchemy import Numeric,Table, MetaData, Column, ForeignKey,Integer, String

      engine1 = create_engine('sqlite://')

      engine2 = create_engine('sqlite://')

      metadata = MetaData()

      product_table = Table(

      'product', metadata,

      Column('sku', String(20), primary_key=True),

      Column('msrp', Numeric))

      product_summary_table = Table(

      'product_summary', metadata,

      Column('sku', String(20), ForeignKey('product.sku'), primary_key=True),

      Column('name', Unicode(255)),

      Column('description', Unicode))

      product_table.create(bind=engine1)

      product_summary_table.create(bind=engine2)

      stmt = product_table.insert()

      engine1.execute(

      stmt,

      [dict(sku="123", msrp=12.34),

      dict(sku="456", msrp=22.12),

      dict(sku="789", msrp=41.44)])

      stmt = product_summary_table.insert()

      engine2.execute(

      stmt,

      [dict(sku="123", name="Shoes", description="SomeShoes"),

      dict(sku="456", name="Pants", description="SomePants"),

      dict(sku="789", name="Shirts", description="Some Shirts")])

       

      這樣就創(chuàng)建了表并且插入了一些數(shù)據(jù)

      dongwm@localhost ~ $ python
      Python 2.7.3 (default, Jul 11 2012, 10:10:17)
      [GCC 4.5.3] on linux2
      Type “help”, “copyright”, “credits” or “l(fā)icense” for more information.
      >>> from sqlalchemy import create_engine
      >>> from sqlalchemy.orm import mapper, sessionmaker
      >>> from sqlalchemy import Numeric,Table, MetaData, Column,ForeignKey, Integer, String,Unicode
      >>> engine1 = create_engine(‘sqlite://’)
      >>> engine2 = create_engine(‘sqlite://’)  #創(chuàng)建多個引擎
      >>> metadata = MetaData()
      >>> product_table = Table(
      … ‘product’, metadata,
      … Column(‘sku’, String(20), primary_key=True),
      … Column(‘msrp’, Numeric))
      >>> product_summary_table = Table(
      … ‘product_summary’, metadata,
      … Column(‘sku’, String(20), ForeignKey(‘product.sku’), primary_key=True),
      … Column(‘name’, Unicode(255)),
      … Column(‘description’, Unicode))
      >>> product_table.create(bind=engine1)
      >>> product_summary_table.create(bind=engine2)
      >>> stmt = product_table.insert()
      >>> engine1.execute(
      … stmt,
      … [dict(sku="123", msrp=12.34),
      ... dict(sku="456", msrp=22.12),
      ... dict(sku="789", msrp=41.44)])
      <sqlalchemy.engine.base.ResultProxy object at 0x84ef9ec>
      >>> stmt = product_summary_table.insert()
      >>> engine2.execute(  #用引擎2 插入數(shù)據(jù),那么product_summary的數(shù)據(jù)就在這個引擎
      … stmt,
      … [dict(sku="123", name="Shoes", description="SomeShoes"),
      ... dict(sku="456", name="Pants", description="SomePants"),
      ... dict(sku="789", name="Shirts", description="SomeShirts")])
      /usr/lib/python2.7/site-packages/SQLAlchemy-0.7.8-py2.7-linux-i686.egg/sqlalchemy/engine/default.py:463:SAWarning: Unicode type received non-unicode bind param value.
      param.append(processors[key](compiled_params[key]))
      <sqlalchemy.engine.base.ResultProxy object at 0x84e896c>
      >>> class Product(object):
      …     def __init__(self, sku, msrp, summary=None):
      …         self.sku = sku
      …         self.msrp = msrp
      …         self.summary = summary
      …     def __repr__(self):
      …         return ‘<Product %s>’ %self.sku

      >>> class ProductSummary(object):
      …     def __init__(self, name, description):
      …         self.name = name
      …         self.description =description
      …     def __repr__(self):
      …         return ‘<ProductSummary%s>’ % self.name

      >>> from sqlalchemy.orm import clear_mappers,backref,relation
      >>> clear_mappers()
      >>> mapper(ProductSummary, product_summary_table, properties=dict(
      …     product=relation(Product,
      …                     backref=backref(‘summary’, uselist=False))))
      <Mapper at 0x84efa4c; ProductSummary>
      >>> mapper(Product, product_table)
      <Mapper at 0x84efd0c; Product>
      >>> Session = sessionmaker(binds={Product:engine1,  #這里綁定了2個引擎,不同orm的引擎不同
      …     ProductSummary:engine2})
      >>> session = Session()
      >>> engine1.echo = engine2.echo = True
      >>> session.query(Product).all() #查詢product的數(shù)據(jù)
      2012-07-18 19:00:59,514 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
      2012-07-18 19:00:59,514 INFO sqlalchemy.engine.base.Engine SELECT product.skuAS product_sku, product.msrp AS product_msrp
      FROM product
      2012-07-18 19:00:59,514 INFO sqlalchemy.engine.base.Engine ()
      /usr/lib/python2.7/site-packages/SQLAlchemy-0.7.8-py2.7-linux-i686.egg/sqlalchemy/types.py:215:SAWarning: Dialect sqlite+pysqlite does *not* support Decimal objects natively,and SQLAlchemy must convert from floating point – rounding errors and otherissues may occur. Please consider storing Decimal numbers as strings orintegers on this platform for lossless storage.
      d[coltype] = rp = d['impl'].result_processor(dialect, coltype)
      [<Product 123>, <Product 456>, <Product 789>]
      >>> session.query(ProductSummary).all() #查詢ProductSummary
      2012-07-18 19:01:07,510 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
      2012-07-18 19:01:07,510 INFO sqlalchemy.engine.base.Engine SELECTproduct_summary.sku AS product_summary_sku, product_summary.name ASproduct_summary_name, product_summary.description AS product_summary_description
      FROM product_summary
      2012-07-18 19:01:07,510 INFO sqlalchemy.engine.base.Engine ()
      [<ProductSummary Shoes>, <ProductSummary Pants>, <ProductSummaryShirts>]

      >>> from sqlalchemy.orm.shard import ShardedSession #使用ShardedSession對會話水平分區(qū),根據(jù)需求把數(shù)據(jù)分開
      >>> product_table = Table(
      …     ‘product’, metadata,
      …     Column(‘sku’, String(20), primary_key=True),
      …     Column(‘msrp’, Numeric))
      >>> metadata.create_all(bind=engine1)
      >>> metadata.create_all(bind=engine2)
      >>> class Product(object):
      …     def __init__(self, sku, msrp):
      …         self.sku = sku
      …         self.msrp = msrp
      …     def __repr__(self):
      …         return ‘<Product %s>’ %self.sku

      >>> clear_mappers()
      >>> product_mapper = mapper(Product, product_table)
      >>> def shard_chooser(mapper, instance, clause=None):  #返回包含映射和實例的行的分區(qū)ID
      …     if mapper is not product_mapper: #非設(shè)定的orm映射叫做odd
      …         return ‘odd’
      …     if (instance.sku  #數(shù)據(jù)為偶數(shù)也叫做even
      …         and instance.sku[0].isdigit()
      …         and int(instance.sku[0]) % 2== 0):
      …         return ‘even’
      …     else:
      …         return ‘odd’ #否則叫做odd

      >>> def id_chooser(query, ident):  根據(jù)查詢和映射類的主鍵返回對象想通過查詢駐留的shard ID列表
      …     if query.mapper is not product_mapper:
      …         return ['odd']
      …     if (ident \
      …         and ident[0].isdigit()
      …         and int(ident[0]) % 2 == 0):
      …         return ['even']
      …     return ['odd']

      >>> def query_chooser(query): #返回可選的shard ID列表
      …     return ['even', 'odd']

      >>> Session = sessionmaker(class_=ShardedSession)
      >>> session = Session(
      …     shard_chooser=shard_chooser,
      …     id_chooser=id_chooser,
      …     query_chooser=query_chooser,
      …     shards=dict(even=engine1,
      …                odd=engine2))
      >>> products = [ Product('%d%d%d' % (i,i,i), 0.0)
      ...     for i in range(10) ]
      >>> for p in products:
      …     session.add(p)

      >>> session.flush()
      >>> for row in engine1.execute(product_table.select()):
      …     print row

      2012-07-18 19:11:19,811 INFO sqlalchemy.engine.base.Engine SELECT product.sku,product.msrp
      FROM product
      2012-07-18 19:11:19,811 INFO sqlalchemy.engine.base.Engine ()
      (u’000′, Decimal(’0E-10′)) #偶數(shù)數(shù)據(jù)寫在engine1
      (u’222′, Decimal(’0E-10′))
      (u’444′, Decimal(’0E-10′))
      (u’666′, Decimal(’0E-10′))
      (u’888′, Decimal(’0E-10′))
      >>> for row in engine2.execute(product_table.select()):
      …     print row

      2012-07-18 19:11:40,098 INFO sqlalchemy.engine.base.Engine SELECT product.sku,product.msrp
      FROM product
      2012-07-18 19:11:40,099 INFO sqlalchemy.engine.base.Engine ()
      (u’111′, Decimal(’0E-10′)) #奇數(shù)數(shù)據(jù)寫在engine1
      (u’333′, Decimal(’0E-10′))
      (u’555′, Decimal(’0E-10′))
      (u’777′, Decimal(’0E-10′))
      (u’999′, Decimal(’0E-10′))
      >>> session.query(Product).all()
      2012-07-18 19:12:36,130 INFO sqlalchemy.engine.base.Engine SELECT product.skuAS product_sku, product.msrp AS product_msrp
      FROM product
      2012-07-18 19:12:36,130 INFO sqlalchemy.engine.base.Engine ()
      2012-07-18 19:12:36,131 INFO sqlalchemy.engine.base.Engine SELECT product.skuAS product_sku, product.msrp AS product_msrp
      FROM product
      2012-07-18 19:12:36,131 INFO sqlalchemy.engine.base.Engine ()
      [<Product 123>, <Product 456>, <Product 789>, <Product000>, <Product 222>, <Product 444>, <Product 666>,<Product 888>, <Product 111>, <Product 333>, <Product555>, <Product 777>, <Product 999>]

      from sqlalchemy import create_engine
      from sqlalchemy.orm import mapper, sessionmaker
      from datetime import datetime
      from sqlalchemy import Numeric,Table, MetaData, Column, ForeignKey, Integer,String, Unicode, DateTime
      from sqlalchemy import types
      from sqlalchemy.databases import sqlite
      engine1 = create_engine(‘sqlite://’)
      engine2 = create_engine(‘sqlite://’)
      metadata = MetaData()
      product_table = Table(
      ‘product’, metadata,
      Column(‘sku’, String(20), primary_key=True),
      Column(‘msrp’, Numeric))
      product_summary_table = Table(
      ‘product_summary’, metadata,
      Column(‘sku’, String(20), ForeignKey(‘product.sku’), primary_key=True),
      Column(‘name’, Unicode(255)),
      Column(‘description’, Unicode))
      product_table.create(bind=engine1)
      product_summary_table.create(bind=engine2)
      stmt = product_table.insert()
      engine1.execute(
      stmt,
      [dict(sku="123", msrp=12.34),
      dict(sku="456", msrp=22.12),
      dict(sku="789", msrp=41.44)])
      stmt = product_summary_table.insert()
      engine2.execute(
      stmt,
      [dict(sku="123", name="Shoes", description="SomeShoes"),
      dict(sku="456", name="Pants", description="SomePants"),
      dict(sku="789", name="Shirts", description="SomeShirts")])

       本文主要說刪除

      metadata.drop_all(engine) #刪除某引擎的全部表

      metadata.remove(test_table)  #刪除某一個table

      clear_mappers() #取消所有的映射

      在relation中有一個參數(shù)cascade,它是基于session的操作,包括把對象放入session,從session刪除對象等,如果 指定cascade=”all”表示做的任何session操作給映射類都能很好的工作,默認包含save-update, merge
      mapper(ParentClass, parent, properties=dict(
      children=relation(ChildClass, backref=’parent’,
      cascade=’all,delete-orphan’) )) #delete-orphan表示如果曾經(jīng)是子類(childclass)實例但是卻沒有和父類連接的情況下,假如要刪除這個子類,而不想掛空父類引用了的實例,
      額看個例子就懂了:
      photo = Table(
      … ‘photo’, metadata,
      … Column(‘id’, Integer, primary_key=True))
      tag = Table(
      … ‘tag’, metadata,
      … Column(‘id’, Integer, primary_key=True),
      … Column(‘photo_id’, None, ForeignKey(‘photo.id’)),
      … Column(‘tag’, String(80)))
      class Photo(object):
      … pass

      class Tag(object):
      … def __init__(self, tag):
      … self.tag = tag

      mapper(Photo, photo, properties=dict(
      … tags=relation(Tag, backref=’photo’, cascade=”all”)))
      <Mapper at 0x851504c; Photo>
      >>> mapper(Tag, tag)
      <Mapper at 0x8515dac; Tag>
      >>> p1 = Photo()
      >>> p2 = Photo()
      >>> p1.tags = [Tag(tag='foo'),Tag(tag='bar'),Tag(tag='baz')]
      >>> p2.tags = [Tag(tag='foo'),Tag(tag='bar'),Tag(tag='baz')]
      >>> session.add(p1)
      >>> session.add(p2)
      >>> session.flush()
      >>> for t in session.query(Tag):
      … print t.id,t.photo_id, t.tag

      1 1 foo #出現(xiàn)以下關(guān)聯(lián)數(shù)據(jù)
      2 1 bar
      3 1 baz
      4 2 foo
      5 2 bar
      6 2 baz
      >>> session.delete(session.query(Photo).get(1)) #刪除一個tag的數(shù)據(jù)
      >>> session.flush()
      >>> for t in session.query(Tag):
      … print t.id, t.photo_id, t.tag

      4 2 foo #他會刪除關(guān)聯(lián)所有t.photo_id為1的數(shù)據(jù),在這里relation(ChildClass, backref=’parent’,cascade=’all,delete-orphan’)指定delete-orphan沒什么,關(guān)鍵看下面
      5 2 bar
      6 2 baz
      >>> p3 = session.query(Photo).get(2)
      >>> del p3.tags[0] #如果我只是刪除關(guān)聯(lián)點…
      >>> session.flush()
      >>> for t in session.query(Tag):
      … print t.id, t.photo_id, t.tag

      4 None foo #關(guān)聯(lián)點photo_id成了none,但是條目存在 –他不會影響其它關(guān)聯(lián)表
      5 2 bar
      6 2 baz

      >>> p3 = session.query(Photo).get(2) #假如沒有設(shè)置delete-orphan
      >>> del p3.tags[0]
      >>> session.flush()
      >>> for t in session.query(Tag):
      … print t.id, t.photo_id, t.tag
      5 2 bar #自動刪除了關(guān)聯(lián)的其它表的項
      6 2 baz
      注:可用的cascade參數(shù)包含:

      • save-update -我的理解是調(diào)用session.add()會自動將項目添加到相應(yīng)級聯(lián)關(guān)系上,也適用于已經(jīng)從關(guān)系中刪除的項目嗨沒有來得及刷新的情況
      • merge – 它是session.merge的實現(xiàn),復(fù)制狀態(tài)到具有相同標(biāo)識符的持久化實例的實例,如果沒有持久的實例和當(dāng)前session相關(guān)聯(lián),返回的持久化實例。如果給定的實例未保存,他會保存一個副本,并返回這個副本作為一個新的持久化實例
      • expunge – 從session中刪除實例
      • delete – 標(biāo)記一個實例被刪除,執(zhí)行flush()會執(zhí)行刪除操作
      • delete-orphan-如果子類從母類刪除,標(biāo)記之,但是不影響母類
      • refresh-expire – 定期刷新在給定的實例的屬性,查詢并刷新數(shù)據(jù)庫
      • all – 以上全部屬性的集合:“save-update,merge, refresh-expire, expunge, delete

      ·        本文主要是ORM的sission查詢和更新

      ·        session負責(zé)執(zhí)行內(nèi)存中的對象和數(shù)據(jù)庫表之間的同步工作,創(chuàng)建session可以這樣:

      ·        Session =sessionmaker(bind=engine) #sqlalchemy.orm.session.Session類有很多參數(shù),使用sessionmaker是為了簡化這個過程

      ·        或者:
      Session = sessionmaker()
      Session.configure(bind=engine)

      ·        注:sessionmaker的參數(shù):
      autoflush=True  #為True時,session將在執(zhí)行session的任何查詢前自動調(diào)用flush()。這將確保返回的結(jié)果

      ·        transactional=False #為True時,session將自動使用事務(wù)commit
      twophase=False #當(dāng)處理多個數(shù)據(jù)庫實例,當(dāng)使用flush()但是沒有提交事務(wù)commit時,給每個數(shù)據(jù)庫一個標(biāo)識,使整個事務(wù)回滾

      ·        創(chuàng)建session,添加數(shù)據(jù)的例子(以前也出現(xiàn)過很多次了)
      dongwm@localhost ~ $ python
      Python 2.7.3 (default, Jul 11 2012, 10:10:17)
      [GCC 4.5.3] on linux2
      Type “help”, “copyright”, “credits” or “l(fā)icense” for more information.
      >>> from sqlalchemy import *
      >>> from sqlalchemy.orm import *
      >>> engine = create_engine(‘sqlite://’)
      >>> metadata = MetaData(engine)
      >>> account_table = Table(
      … ‘a(chǎn)ccount’, metadata,
      … Column(‘id’, Integer, primary_key=True),
      … Column(‘balance’, Numeric))
      >>> class Account(object): pass

      >>> mapper(Account, account_table)
      <Mapper at 0x84e6f2c; Account>
      >>> account_table.create()
      >>> a = Account()
      >>> a.balance = 100.00
      >>> Session = sessionmaker(bind=engine)
      >>> session = Session()
      >>> session.add(a)
      >>> session.flush()
      >>> session.delete(a) #自動刪除 account_table相應(yīng)條目,但是在1:N和M:N關(guān)系中不會自動刪除它的級聯(lián)關(guān)系
      >>> session.flush()

      ·        注:session的對象狀態(tài):

      ·        Transient:短暫的,主要指內(nèi)存中的對象

      ·        Pending:掛起的,這樣的對象準備插入數(shù)據(jù)庫,等執(zhí)行了flush就會插入

      ·        Persistent:持久的

      ·        Detached:對象在數(shù)據(jù)庫里面有記錄,但是不屬于session

      ·        >>>make_transient(a)  #因為標(biāo)識了已刪除,恢復(fù)a的狀態(tài)
      >>> session.add(a) #重新添加
      >>> session.flush()
      >>> query = session.query(Account)
      >>> print query
      SELECT account.id AS account_id, account.balance AS account_balance
      FROM account
      >>> for obj in query:
      …     print obj

      <__main__.Account object at 0x84eef0c>

      ·        >>> query.all() #查詢所有
      [<__main__.Account object at 0x84eef0c>]
      >>> query = query.filter(Account.balance > 10.00)  #filter過濾
      >>> for obj in query:
      …     print obj.balance

      ·        100.00

      ·        >>> for i insession.query(Account).filter_by(balance=100.00 ):  #通過條件過濾
      …     print i
      >>> query = session.query(Account)
      >>> query = query.from_statement(‘select *from account wherebalance=:bac’) #通過帶通配符的SQL語句其中:bac標(biāo)識這個參數(shù)是bac
      >>> query = query.params(bac=’100.00′) #根據(jù)bac指定值尋找
      >>> print query.all()
      [<__main__.Account object at 0x84eef0c>]

      ·        本地session

      ·        >>> Session =scoped_session(sessionmaker(  #設(shè)置一個本地的共享session
      …     bind=engine, autoflush=True))
      >>> session = Session()
      >>> session2 = Session()
      >>> session is session2  #他們是同一個
      True

      ·        >>> a = Account()
      >>> a.balance = 100.00
      >>> Session.add(a) #注意 這是的’S'是大寫
      >>> Session.flush()
      >>> b = Account()
      >>> a.balance = 200.00
      >>> session.add(a)  #其實他們是一個共享的session 名字都可以
      >>> session.flush()
      >>> print session.query(Account).all() #查詢到了2個
      [<__main__.Account object at 0x851be0c>, <__main__.Account object at0x84f7d6c>]

      ·        注:這樣的映射mapper也可以這樣是用:

      ·        mapper(Product, product_table,properties=dict(
      categories=relation(Category, secondary=product_category_table,
      backref=’products’)))

      ·        Session.mapper(Product,product_table, properties=dict(
      categories=relation(Category, secondary=product_category_table,
      backref=’products’))) #它的優(yōu)點是可以初始化參數(shù)

      ·        本文主要是面向?qū)ο蟮睦^承映射到關(guān)系數(shù)據(jù)庫表的方法

      ·        >>> classProduct(object):
      …     def __init__(self, sku, msrp):
      …         self.sku = sku
      …         self.msrp = msrp
      …     def __repr__(self):
      …         return ‘<%s %s>’ % (
      …            self.__class__.__name__, self.sku)

      >>> class Clothing(Product):
      …     def __init__(self, sku, msrp, clothing_info):
      …         Product.__init__(self, sku,msrp) #繼承了Product
      …         self.clothing_info =clothing_info

      >>> class Accessory(Product):
      …     def __init__(self, sku, msrp, accessory_info):
      …         Product.__init__(self, sku,msrp) #繼承了Product
      …         self.accessory_info =accessory_info
      也就是這樣的意思:

      ·        

      ·        這個單表繼承中(如下圖,黑色的表示沒有被映射):

      ·        

      ·        從創(chuàng)建表結(jié)構(gòu)是這樣:

      ·        >>> product_table =Table(
      …     ‘product’, metadata,
      …     Column(‘sku’, String(20), primary_key=True),
      …     Column(‘msrp’, Numeric),
      …     Column(‘clothing_info’, String),
      …     Column(‘a(chǎn)ccessory_info’, String),
      …     Column(‘product_type’, String(1), nullable=False)) #一個新的字段
      >>> mapper(
      …     Product, product_table,
      …     polymorphic_on=product_table.c.product_type, #映射繼承層次結(jié)構(gòu)使用polymorphic_on表示繼承在product_type字段,值是polymorphic_identity指定的標(biāo)識
      …     polymorphic_identity=’P') #標(biāo)識繼承 Product ,父類
      <Mapper at 0x85833ec; Product>
      >>> mapper(Clothing, inherits=Product,
      …       polymorphic_identity=’C')   #標(biāo)識繼承Clothingproduct
      <Mapper at 0x858362c; Clothing>
      >>>
      >>> mapper(Accessory, inherits=Product, #繼承至Product
      …        polymorphic_identity=’A') #標(biāo)識繼承Accessory
      <Mapper at 0x8587d8c; Accessory>
      >>> products = [  #創(chuàng)建一些產(chǎn)品
      ...     Product('123', 11.22),
      ...     Product('456', 33.44),
      ...     Clothing('789', 123.45, "Nice Pants"),
      ...     Clothing('111', 125.45, "Nicer Pants"),
      ...     Accessory('222', 24.99, "Wallet"),
      ...     Accessory('333', 14.99, "Belt") ]
      >>> Session = sessionmaker()
      >>> session = Session()
      >>> for p in products:
      …     session.add(p)

      >>> session.flush()
      >>> print session.query(Product).all() #全部都有
      [<Product 123>, <Product 456>, <Clothing 789>, <Clothing111>, <Accessory 222>, <Accessory 333>]
      >>> print session.query(Clothing).all()  #只顯示2個
      [<Clothing 789>, <Clothing 111>]
      >>> print session.query(Accessory).all() #只顯示2個,是不是上面的映射效果和創(chuàng)建3個類而分別orm好的多呢?
      [<Accessory 222>, <Accessory 333>]

      ·        >>> for row inproduct_table.select().execute(): #從父類庫查詢,所有數(shù)據(jù)都有,只是product_type不同
      …     print row

      (u’123′, Decimal(’11.2200000000′), None, None, u’P')
      (u’456′, Decimal(’33.4400000000′), None, None, u’P')
      (u’789′, Decimal(’123.4500000000′), u’Nice Pants’, None, u’C')
      (u’111′, Decimal(’125.4500000000′), u’Nicer Pants’, None, u’C')
      (u’222′, Decimal(’24.9900000000′), None, u’Wallet’, u’A')
      (u’333′, Decimal(’14.9900000000′), None, u’Belt’, u’A')

      ·        具體的映射見下圖:

      ·        

      ·        查詢一個沒有的不存在的映射:

      ·        >>> printsession.query(Accessory)[0].clothing_info
      None

      ·        具體表的繼承

      ·        每個表包含的數(shù)據(jù)量,需要實現(xiàn)它的類;沒有浪費的空間

      ·        >>>metadata.remove(product_table)
      >>> product_table = Table(
      …     ‘product’, metadata,
      …     Column(‘sku’, String(20), primary_key=True),
      …     Column(‘msrp’, Numeric))
      >>> clothing_table = Table(
      …     ‘clothing’, metadata,
      …     Column(‘sku’, String(20), primary_key=True),
      …     Column(‘msrp’, Numeric),
      …     Column(‘clothing_info’, String))
      >>>
      >>> accessory_table = Table(
      …     ‘a(chǎn)ccessory’, metadata,
      …     Column(‘sku’, String(20), primary_key=True),
      …     Column(‘msrp’, Numeric),
      …     Column(‘a(chǎn)ccessory_info’, String))
      >>>
      攝像我們想要獲取Product’sku’是222的數(shù)據(jù)(沒有其他額外的工作),我們不得不層次型的查詢每個類,請看這個例子:

      ·        >>> punion =polymorphic_union(
      …     dict(P=product_table,
      …     C=clothing_table,
      …     A=accessory_table),
      …     ‘type_’)
      >>>
      >>> print punion
      SELECT accessory.sku, accessory.msrp, accessory.accessory_info, CAST(NULL ASVARCHAR) AS clothing_info, ‘A’ AS type_
      FROM accessory UNION ALL SELECT product.sku, product.msrp, CAST(NULL ASVARCHAR) AS accessory_info, CAST(NULL AS VARCHAR) AS clothing_info, ‘P’ AStype_
      FROM product UNION ALL SELECT clothing.sku, clothing.msrp, CAST(NULL ASVARCHAR) AS accessory_info, clothing.clothing_info, ‘C’ AS type_
      FROM clothing
      現(xiàn)在我們就有了一個很好的標(biāo)記了(C,A,P)

      ·        >>> mapper(
      …     Product, product_table, with_polymorphic=(‘*’,punion),  #使用with_polymorphic=(‘*’, punion)的方式映射父類,指定不同表選擇,實現(xiàn)多態(tài),并且提高了性能(只select了一次)
      …     polymorphic_on=punion.c.type_,
      …     polymorphic_identity=’P')
      <Mapper at 0x8605b6c; Product>
      >>> mapper(Clothing, clothing_table, inherits=Product,
      … polymorphic_identity=’C',
      … concrete=True)
      <Mapper at 0x84f1bac; Clothing>
      >>> mapper(Accessory, accessory_table, inherits=Product,
      … polymorphic_identity=’A',
      … concrete=True)
      <Mapper at 0x858770c; Accessory>

      ·        >>> session.query(Product).get(’222′)
      <Accessory 222>

      ·        本文主要是講關(guān)于sqlalchemy的擴展

      ·        擴展其實就是一些外部的插件,比如sqlsoup,associationproxy,declarative,horizontal_shard等等

      ·        1 declarative

      ·        假如想要數(shù)據(jù)映射,以前的做法是:

      Source code

         

      ·        from sqlalchemy importcreate_engine

      ·        from sqlalchemy import Column,MetaData, Table

      ·        from sqlalchemy import Integer,String, ForeignKey

      ·        from sqlalchemy.orm importmapper, sessionmaker

      ·        class User(object): #簡單類

      ·            def __init__(self, name, fullname,password):

      ·                self.name = name

      ·                self.fullname = fullname

      ·                self.password = password

      ·            def __repr__(self):

      ·                return "<User('%s','%s','%s')>" % (self.name, self.fullname, self.password)

      ·        metadata = MetaData()

      ·        users_table = Table('users',metadata,

      ·        Column('user_id', Integer,primary_key=True),

      ·        Column('name', String),

      ·        Column('fullname', String),

      ·        Column('password', String)

      ·        )

      ·        email_table = Table('email',metadata,

      ·        Column('email_id', Integer,primary_key=True),

      ·        Column('email_address',String),

      ·        Column('user_id', Integer,ForeignKey('users.user_id'))

      ·        )

      ·        metadata.create_all(engine)

      ·        mapper(User, users_table) #映射

      ·        但是我們可以該換風(fēng)格,可以用這樣的方法:

      Source code

         

      ·        from sqlalchemy import Column,Integer, String, ForeignKey

      ·        from sqlalchemy importcreate_engine

      ·        from sqlalchemy.ext.declarativeimport declarative_base

      ·        from sqlalchemy.orm importbackref, mapper, relation, sessionmaker

      ·        Base = declarative_base()

      ·        class User(Base):

      ·            __tablename__ = "users" #設(shè)定接收映射的表名

      ·            id = Column(Integer, primary_key=True) #將表結(jié)構(gòu)寫到類里面

      ·            name = Column(String)

      ·            fullname = Column(String)

      ·            password = Column(String)

      ·            def __init__(self, name, fullname,password):

      ·                self.name = name

      ·                self.fullname = fullname

      ·                self.password = password

      ·            def __repr__(self):

      ·                return "<User('%s','%s','%s')>" % (self.name, self.fullname, self.password)

      ·        class Address(Base):

      ·            __tablename__ = "addresses"

      ·            id = Column(Integer, primary_key=True)

      ·            email_address = Column(String,nullable=False)

      ·            user_id = Column(Integer,ForeignKey('users.id'))

      ·            user = relation(User,backref=backref('addresses', order_by=id)) #創(chuàng)建雙向關(guān)系,標(biāo)識以user的id為連接,也就是說:Address到User是多對一,User到Address是一對多

      ·            def __init__(self, email_address):

      ·                self.email_address = email_address

      ·            def __repr__(self):

      ·                return"<Address('%s')>" % self.email_address

      ·        engine =create_engine("sqlite:///tutorial.db", echo=True)

      ·        users_table = User.__table__ #獲取User表對象句柄

      ·        metadata = Base.metadata #獲取metadata句柄

      ·        metadata.create_all(engine)

      ·        下面具體說:

      ·        engine =create_engine(‘sqlite://’) #創(chuàng)建引擎
      Base.metadata.create_all(engine) #常見表
      Base.metadata.bind = create_engine(‘sqlite://’) #綁定
      Base = declarative_base(bind=create_engine(‘sqlite://’)) #綁定引擎
      mymetadata = MetaData()
      Base = declarative_base(metadata=mymetadata) #設(shè)定元數(shù)據(jù)設(shè)定簡單關(guān)系:
      class User(Base):
      __tablename__ = ‘users’id = Column(Integer, primary_key=True)
      name = Column(String(50))
      addresses = relationship(“Address”, backref=”user”) #relationship其實就是relation的全稱

      ·        classAddress(Base):
      __tablename__ = ‘a(chǎn)ddresses’

      ·        id =Column(Integer, primary_key=True)
      email = Column(String(50))
      user_id = Column(Integer, ForeignKey(‘users.id’))
      設(shè)定多對多關(guān)系:
      keywords = Table(
      ‘keywords’, Base.metadata,
      Column(‘a(chǎn)uthor_id’, Integer, ForeignKey(‘a(chǎn)uthors.id’)),
      Column(‘keyword_id’, Integer, ForeignKey(‘keywords.id’))
      )
      class Author(Base):
      __tablename__ = ‘a(chǎn)uthors’
      id = Column(Integer, primary_key=True)
      keywords = relationship(“Keyword”, secondary=keywords)
      定義SQL表達式:
      class MyClass(Base):
      __tablename__ = ‘sometable’
      __table_args__ = {‘mysql_engine’:'InnoDB’} #名字,映射類,元數(shù)據(jù)之外的指定需要使用__table_args__

      ·        或者:
      class MyClass(Base):
      __tablename__ = ‘sometable’
      __table_args__ = (
      ForeignKeyConstraint(['id'], ['remote_table.id']), #元組方式
      UniqueConstraint(‘foo’),
      )

      ·        或者:
      class MyClass(Base):
      __tablename__ = ‘sometable’
      __table_args__ = (
      ForeignKeyConstraint(['id'], ['remote_table.id']),
      UniqueConstraint(‘foo’),
      {‘a(chǎn)utoload’:True} #最后的參數(shù)可以用字典 想想*argsand **kwargs
      )
      使用混合式:
      class MyClass(Base):
      __table__ = Table(‘my_table’, Base.metadata, #在__table__里指定表結(jié)構(gòu)
      Column(‘id’, Integer, primary_key=True),
      Column(‘name’, String(50))
      )
      2 sqlsoup(在sqlalchemy0.8版本后他變成了一個獨立的項目,http://pypi./pypi/sqlsoup,

      ·        而我使用gentoo提供的0.7.8版本,以下的程序import部分可能不適用更高版本,而需要import sqlsoup)

      ·        sqlsoup提供一個方便的訪問數(shù)據(jù)庫的接方式,而無需創(chuàng)建類,映射數(shù)據(jù)庫

      ·        還是看例子的對比:

      ·        用以前的方式創(chuàng)建一個數(shù)據(jù)庫并且插入一些數(shù)據(jù):

      ·        >>> fromsqlalchemy import *
      >>> engine = create_engine(‘sqlite:///dongwm.db’)
      >>> metadata = MetaData(engine)
      >>> product_table = Table(
      …     ‘product’, metadata,
      …     Column(‘sku’, String(20), primary_key=True),
      …     Column(‘msrp’, Numeric))
      >>> store_table = Table(
      …     ‘store’, metadata,
      …     Column(‘id’, Integer, primary_key=True),
      …     Column(‘name’, Unicode(255)))
      >>> product_price_table = Table(
      …     ‘product_price’, metadata,
      … Column(‘sku2′, None, ForeignKey(‘product.sku’), primary_key=True),
      … Column(‘store_id’, None, ForeignKey(‘store.id’), primary_key=True),
      …     Column(‘price’, Numeric, default=0))
      >>> metadata.create_all()
      >>> stmt = product_table.insert()
      >>> stmt.execute([dict(sku="123", msrp=12.34),
      ...              dict(sku="456", msrp=22.12),
      ...              dict(sku="789", msrp=41.44)])
      <sqlalchemy.engine.base.ResultProxy object at 0x84fbdcc>
      >>> stmt = store_table.insert()
      >>> stmt.execute([dict(name="Main Store"),
      ...              dict(name="Secondary Store")])
      <sqlalchemy.engine.base.ResultProxy object at 0x850068c>
      >>> stmt = product_price_table.insert()
      >>> stmt.execute([dict(store_id=1, sku="123"),
      ...              dict(store_id=1, sku2="456"),
      ...              dict(store_id=1, sku2="789"),
      ...              dict(store_id=2, sku2="123"),
      ...              dict(store_id=2, sku2="456"),
      ...              dict(store_id=2, sku2="789")])
      <sqlalchemy.engine.base.ResultProxy object at 0x85008cc>
      創(chuàng)建插入完畢,然后我們用sqlsoup連接操作:

      ·        >>> fromsqlalchemy.ext.sqlsoup import SqlSoup
      >>> db = SqlSoup(‘sqlite:///dongwm.db’)  #連接一個存在的數(shù)據(jù)庫
      >>> print db.product.all() #打印結(jié)果
      [MappedProduct(sku=u'123',msrp=Decimal('12.3400000000')),MappedProduct(sku=u'456',msrp=Decimal('22.1200000000')),MappedProduct(sku=u'789',msrp=Decimal('41.4400000000'))]
      >>> print db.product.get(’123′) #是不是比session.query(Product)簡單呢?
      MappedProduct(sku=u’123′,msrp=Decimal(’12.3400000000′))

      ·        注:假如想創(chuàng)建一個數(shù)據(jù)庫: db = SqlSoup(‘sqlite:///:memory:’)

      ·        >>>newprod = db.product.insert(sku=’111′, msrp=22.44) #沒有使用數(shù)據(jù)映射的插入
      >>> db.flush()
      >>> db.clear() #調(diào)用底層,清除所有session實例,它是session.expunge_all的別名
      >>> db.product.all()
      [MappedProduct(sku=u'123',msrp=Decimal('12.3400000000')),MappedProduct(sku=u'456',msrp=Decimal('22.1200000000')),MappedProduct(sku=u'789',msrp=Decimal('41.4400000000')),MappedProduct(sku=u'111',msrp=Decimal('22.4400000000'))] #新條目已經(jīng)存在了
      #MappedProduct使用__getattr__將無法識別的屬性和訪問方法轉(zhuǎn)發(fā)到它的query屬性,它還提供了一些數(shù)據(jù)處理功能用于更新

      ·        >>> fromsqlalchemy import or_, and_, desc
      >>> where = or_(db.product.sku==’123′, db.product.sku==’111′)
      >>> db.product.filter(where).order_by(desc(db.product.msrp)).all() #這樣使用多條件過濾,降序排練
      [MappedProduct(sku='111',msrp=22.44), MappedProduct(sku=u'123',msrp=Decimal('12.3400000000'))]

      ·        >>> join1= db.join(db.product, db.product_price, isouter=True) #關(guān)聯(lián)2個表, isouter=True確保LEFT OUTER(還沒理解)
      >>> join1.all()
      [MappedJoin(sku=u'123',msrp=Decimal('12.3400000000'),sku2=u'123',store_id=1,price=Decimal('0E-10')), #這個字段包含了2個表的相應(yīng)字段
      MappedJoin(sku=u'123',msrp=Decimal('12.3400000000'),sku2=u'123',store_id=2,price=Decimal('0E-10')),MappedJoin(sku=u'456',msrp=Decimal('22.1200000000'),sku2=u'456',store_id=1,price=Decimal('0E-10')),MappedJoin(sku=u'456',msrp=Decimal('22.1200000000'),sku2=u'456',store_id=2,price=Decimal('0E-10')),MappedJoin(sku=u'789',msrp=Decimal('41.4400000000'),sku2=u'789',store_id=1,price=Decimal('0E-10')),MappedJoin(sku=u'789',msrp=Decimal('41.4400000000'),sku2=u'789',store_id=2,price=Decimal('0E-10')),MappedJoin(sku=u'111',msrp=Decimal('22.4400000000'),sku2=None,store_id=None,price=None)]
      >>> join2 = db.join(join1, db.store, isouter=True) #將store表也關(guān)聯(lián)進來(因為也有一個外鍵),就是關(guān)聯(lián)三個表
      >>> join2.all()
      [MappedJoin(sku=u'123',msrp=Decimal('12.3400000000'),sku2=u'123',store_id=1,price=Decimal('0E-10'),id=1,name=u'MainStore'),MappedJoin(sku=u'123',msrp=Decimal('12.3400000000'),sku2=u'123',store_id=2,price=Decimal('0E-10'),id=2,name=u'SecondaryStore'), MappedJoin(sku=u'456',msrp=Decimal('22.1200000000'),sku2=u'456',store_id=1,price=Decimal('0E-10'),id=1,name=u'MainStore'),MappedJoin(sku=u'456',msrp=Decimal('22.1200000000'),sku2=u'456',store_id=2,price=Decimal('0E-10'),id=2,name=u'SecondaryStore'), MappedJoin(sku=u'789',msrp=Decimal('41.4400000000'),sku2=u'789',store_id=1,price=Decimal('0E-10'),id=1,name=u'MainStore'),MappedJoin(sku=u'789',msrp=Decimal('41.4400000000'),sku2=u'789',store_id=2,price=Decimal('0E-10'),id=2,name=u'SecondaryStore'), MappedJoin(sku=u'111',msrp=Decimal('22.4400000000'),sku2=None,store_id=None,price=None,id=None,name=None)]
      >>> join3 = db.with_labels(join1) #根據(jù)原籍標(biāo)記,比如sku會說出:product_sku,告訴你它來著product表,但是指定了jion1,就不會標(biāo)識關(guān)于store的表
      >>> join3.first()
      MappedJoin(product_sku=u’123′,product_msrp=Decimal(’12.3400000000′),product_price_sku2=u’123′,product_price_store_id=1,product_price_price=Decimal(’0E-10′))
      >>> db.with_labels(join2).first()
      MappedJoin(product_sku=u’123′,product_msrp=Decimal(’12.3400000000′),product_price_sku2=u’123′,product_price_store_id=1,product_price_price=Decimal(’0E-10′),store_id=1,store_name=u’MainStore’)
      >>> labelled_product = db.with_labels(db.product)
      >>> join4 = db.join(labelled_product, db.product_price, isouter=True)
      >>> join4.first()
      MappedJoin(product_sku=u’123′,product_msrp=Decimal(’12.3400000000′),sku2=u’123′,store_id=1,price=Decimal(’0E-10′))

      ·        >>>db.clear()
      >>> join5 = db.join(db.product, db.product_price)
      >>> s = select([db.product._table,
      ...     func.avg(join5.c.price).label('avg_price')], #添加一個字段計算產(chǎn)品(product)的price平均值,字段名為avg_price
      …     from_obj=[join5._table],
      …     group_by=[join5.c.sku])
      >>> s = s.alias(‘products_with_avg_price’) #它是fromsqlalchemy import alias; a = alias(self, name=name)的簡寫
      >>> products_with_avg_price = db.map(s, primary_key=[join5.c.sku]) #因為沒有映射到表或者join,需要指定如何找到主鍵
      >>> products_with_avg_price.all()
      [MappedJoin(sku=u'123',msrp=Decimal('12.3400000000'),avg_price=0.0),MappedJoin(sku=u'456',msrp=Decimal('22.1200000000'),avg_price=0.0),MappedJoin(sku=u'789',msrp=Decimal('41.4400000000'),avg_price=0.0)]
      >>> db.product_price.first().price = 50.00
      >>> db.flush()
      >>> products_with_avg_price.all()
      [MappedJoin(sku=u'123',msrp=Decimal('12.3400000000'),avg_price=0.0),MappedJoin(sku=u'456',msrp=Decimal('22.1200000000'),avg_price=0.0),MappedJoin(sku=u'789',msrp=Decimal('41.4400000000'),avg_price=0.0)]
      >>> db.products_with_avg_price = products_with_avg_price #保存映射到db,方便重用
      >>> msrp=select([db.product.c.msrp],
      …     db.product.sku==db.product_price.sku2) #獲取sku和sku2相等時候msrp的值
      >>> db.product_price.update(  #更新數(shù)據(jù)
      …     values=dict(price=msrp),synchronize_session=False) #設(shè)置price這個字段值為上面對應(yīng)的msrp

      ·        6
      >>> db.product_price.all()
      [MappedProduct_price(sku2=u'123',store_id=1,price=Decimal('12.3400000000')),MappedProduct_price(sku2=u'456',store_id=1,price=Decimal('22.1200000000')),MappedProduct_price(sku2=u'789',store_id=1,price=Decimal('41.4400000000')),MappedProduct_price(sku2=u'123',store_id=2,price=Decimal('12.3400000000')),MappedProduct_price(sku2=u'456',store_id=2,price=Decimal('22.1200000000')),MappedProduct_price(sku2=u'789',store_id=2,price=Decimal('41.4400000000'))]

      ·        3 associationproxy

      ·        associationproxy用于創(chuàng)建一個讀/寫整個關(guān)系的目標(biāo)屬性

      ·        看一個例子就懂了:

      ·        >>>user_table = Table(
      …     ‘user’, metadata,
      …     Column(‘id’, Integer, primary_key=True),
      …     Column(‘user_name’, String(255), unique=True),
      …     Column(‘password’, String(255)))
      >>> brand_table = Table(
      …     ‘brand’, metadata,
      …     Column(‘id’, Integer, primary_key=True),
      …     Column(‘name’, String(255)))
      >>> sales_rep_table = Table(
      …     ‘sales_rep’, metadata,
      … Column(‘brand_id’, None, ForeignKey(‘brand.id’), primary_key=True),
      … Column(‘user_id’, None, ForeignKey(‘user.id’), primary_key=True),
      …     Column(‘commission_pct’, Integer, default=0))
      >>> class User(object): pass

      >>> class Brand(object): pass

      >>> class SalesRep(object): pass

      >>> mapper(User, user_table, properties=dict(
      …     sales_rep=relation(SalesRep, backref=’user’,uselist=False)))
      <Mapper at 0x87472ec; User>
      >>> mapper(Brand, brand_table, properties=dict(
      …     sales_reps=relation(SalesRep, backref=’brand’)))
      <Mapper at 0x874770c; Brand>
      >>> mapper(SalesRep, sales_rep_table)
      <Mapper at 0x874768c; SalesRep>

      ·        ORM完成,但是假如我們想要brand(品牌)類對象的一個所有SalesReps for Brand(品牌的銷售代表)的User列表屬性,可以這樣:

      ·        classBrand(object):
      @property
      def users(self):
      return [ sr.user for sr in self.sales_reps ]

      ·        但是不方便增加刪除,而使用association_proxy:

      ·        >>> fromsqlalchemy.ext.associationproxy import association_proxy
      >>> class Brand(object):
      …        users=association_proxy(‘sales_reps’, ‘user’)

      ·        或者:

      ·        mapper(Brand,brand_table, properties=dict(
      sales_reps=relation(SalesRep, backref=’brand’)))
      Brand.users=association_proxy(‘sales_reps’, ‘user’)#優(yōu)點是維持了域?qū)ο?/p>

      ·        我們需要修改類,增加屬性:

      ·        classUser(object):
      def __init__(self, user_name=None, password=None):
      self.user_name=user_name
      self.password=password

      ·        classBrand(object):
      def __init__(self, name=None):
      self.name = name

      ·        classSalesRep(object):
      def __init__(self, user=None, brand=None, commission_pct=0):
      self.user = user
      self.brand = brand
      self.commission_pct=commission_pct

      ·        看下面的效果:

      ·        >>> b =Brand(‘Cool Clothing’)
      >>> session.add(b)
      >>> u = User(‘rick’, ‘foo’)
      >>> session.add(u)
      >>> session.flush()
      2012-07-20 12:22:33,191 INFO sqlalchemy.engine.base.Engine INSERT INTO user(user_name, password) VALUES (?, ?)
      2012-07-20 12:22:33,191 INFO sqlalchemy.engine.base.Engine (‘rick’, ‘foo’)
      2012-07-20 12:22:33,191 INFO sqlalchemy.engine.base.Engine INSERT INTO brand(name) VALUES (?)
      2012-07-20 12:22:33,191 INFO sqlalchemy.engine.base.Engine (‘Cool Clothing’,)
      >>> b.users
      2012-07-20 12:22:42,135 INFO sqlalchemy.engine.base.Engine SELECTsales_rep.brand_id AS sales_rep_brand_id, sales_rep.user_id ASsales_rep_user_id, sales_rep.commission_pct AS sales_rep_commission_pct
      FROM sales_rep
      WHERE ? = sales_rep.brand_id
      2012-07-20 12:22:42,135 INFO sqlalchemy.engine.base.Engine (2,)
      []
      >>> b.users.append(u) #自動創(chuàng)建一個單一的位置參數(shù)調(diào)用其中介(SalesRep)對象
      2012-07-20 12:22:46,782 INFO sqlalchemy.engine.base.Engine SELECTsales_rep.brand_id AS sales_rep_brand_id, sales_rep.user_id ASsales_rep_user_id, sales_rep.commission_pct AS sales_rep_commission_pct
      FROM sales_rep
      WHERE ? = sales_rep.user_id
      2012-07-20 12:22:46,782 INFO sqlalchemy.engine.base.Engine (2,)
      >>> b.users
      [<__main__.User object at 0x87d7b6c>]
      >>> b.sales_reps
      [<__main__.SalesRep object at 0x87d7c4c>]
      >>> b.sales_reps[0].commission_pct
      0
      >>> session.flush()
      2012-07-20 12:23:14,215 INFO sqlalchemy.engine.base.Engine INSERT INTOsales_rep (brand_id, user_id, commission_pct) VALUES (?, ?, ?)
      2012-07-20 12:23:14,215 INFO sqlalchemy.engine.base.Engine (2, 2, 0)

      ·        更復(fù)雜的想法給銷售人員一個10%的提成:

      ·        Brand.users=association_proxy(
      ‘sales_reps’, ‘user’,
      creator=lambda u:SalesRep(user=u, commission_pct=10))

      ·        假設(shè)我們想要的品牌屬性是一個附帶User和傭金commission_pct的字典:

      ·        fromsqlalchemy.orm.collections import attribute_mapped_collection
      >>> from sqlalchemy.orm.collections import attribute_mapped_collection
      >>> reps_by_user_class=attribute_mapped_collection(‘user’)
      >>> clear_mappers()
      >>> mapper(Brand, brand_table, properties=dict(
      …     sales_reps_by_user=relation(
      …         SalesRep, backref=’brand’,
      …        collection_class=reps_by_user_class)))
      <Mapper at 0x862c5ec; Brand>

      ·        >>>Brand.commissions=association_proxy(
      …     ‘sales_reps_by_user’, ‘commission_pct’,
      …     creator=lambda key,value: SalesRep(user=key,commission_pct=value))
      >>> mapper(User, user_table, properties=dict(
      …     sales_rep=relation(SalesRep, backref=’user’,uselist=False)))
      <Mapper at 0x8764b2c; User>
      >>> mapper(SalesRep, sales_rep_table)
      <Mapper at 0x87bb4cc; SalesRep>
      >>> b = session.query(Brand).get(1)
      >>> u = session.query(User).get(1)
      >>> b.commissions[u] = 20
      >>> session.bind.echo = False
      >>> session.flush()
      >>> b = session.query(Brand).get(1)
      >>> u = session.query(User).get(1)
      >>> u.user_name
      u’dongwm’
      >>> print b.commissions[u]
      20
      >>> print b.sales_reps_by_user[u] #代理和原來的關(guān)系是自動同步的
      <__main__.SalesRep object at 0x87e3dcc>
      >>> print b.sales_reps_by_user[u].commission_pct
      20

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多