sqlalchemy 查找表

1 投票
3 回答
2169 浏览
提问于 2025-04-15 17:23

你好,我有一个符合第三范式的表格

ftype_table = Table(
    'FTYPE',
    Column('ftypeid', Integer, primary_key=True),
    Column('typename', String(50)),
    base.metadata,
    schema='TEMP')
file_table = Table(
    'FILE',
    base.metadata,
    Column('fileid', Integer, primary_key=True),
    Column('datatypeid', Integer, ForeignKey(ftype_table.c.datatypeid)),
    Column('size', Integer),
    schema='TEMP')                                                                

还有一些映射器

class File(object): pass
class FileType(object): pass
mapper(File, file_table, properties={'filetype': relation(FileType)})
mapper(FileType, file_table)

假设Ftype表里有1:TXT、2:AVI、3:PPT这些类型

我想做的是,如果我这样创建一个文件对象:

file=File()
file.size=10
file.filetype= FileType('PPT')
Session.save(file)
Session.flush()

那么File表里会包含fileid:xxx,size:10,datatypeid:3

不幸的是,这样会在FileType表里添加一条记录,而这个ID也会传到File表里。

有没有什么聪明的方法可以用sqlalchemy来实现这个,而不需要去查询FileType表来检查这个条目是否存在呢?

谢谢

3 个回答

0

只需要创建一个文件类型对象的缓存,这样在你第一次使用某种文件类型时,数据库查询只会发生一次:

class FileTypeCache(dict):
    def __missing__(self, key):
        obj = self[key] = Session.query(FileType).filter_by(typename=key).one()
        return obj

filetype_cache = FileTypeCache()

file=File()
file.size=10
file.filetype= filetype_cache['PPT']

这样应该可以正常工作,前提是没有拼写错误。

2

这里提到的UniqueObject方法是一个标准的解决方案,具体可以查看这个链接:http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject。这个方法的核心思想是重写File的创建过程,使用__metaclass__.call()或者File.__new__(),这样可以返回已经存在的对象,这个对象可能来自数据库或者缓存(如果对象在数据库中不存在,第一次查找是不可避免的,除非使用了围绕MySQL的REPLACE构建的某种方法)。

补充一下:因为我一直在研究使用方法,所以我对这个唯一对象的方法进行了重写,使其更易于移植,并且更新到了0.5/0.6版本。

0

因为 declarative_base 和 zzzeek 的代码在 sqlalchemy 0.4 版本中无法使用,所以我用了下面的缓存,这样即使新对象不在数据库中,它们也能保持唯一性。

class FileTypeCache(dict):
    def __missing__(self, key):
        try:
          obj = self[key] = Session.query(FileType).filter_by(typename=key).one()
          return obj
        except InvalidRequestError:
          return obj=self[key]= FileType(key)
          return obj

重写 eq 方法来处理 FileType。

class FileType(object):
    def __init__(self, typename)
       self.typename=typename
    def __eq__(self):
        if isinstance(other, FileType):
            return self.typename == other.typename
        else:
            return False

撰写回答