【问题标题】:Importing fixtures with foreign keys and SQLAlchemy?使用外键和 SQLAlchemy 导入夹具?
【发布时间】:2010-06-02 23:20:54
【问题描述】:

我一直在尝试使用夹具将测试数据集加载到我的 Pylons / PostgreSQL 应用程序中。这很好用,但如果外键引用自动增量 id 字段,则无法正确创建外键。

我的灯具是这样的:

class AuthorsData(DataSet):
    class frank_herbert:
         first_name = "Frank"
         last_name = "Herbert"

class BooksData(DataSet):
    class dune:
        title = "Dune"
        author_id = AuthorsData.frank_herbert.ref('id')

还有模特:

t_authors = sa.Table("authors", meta.metadata,
    sa.Column("id", sa.types.Integer, primary_key=True),
    sa.Column("first_name", sa.types.String(100)),
    sa.Column("last_name", sa.types.String(100)),
    )

t_books = sa.Table("books", meta.metadata,
    sa.Column("id", sa.types.Integer, primary_key=True),
    sa.Column("title", sa.types.String(100)),
    sa.Column("author_id", sa.types.Integer, sa.ForeignKey('authors.id')) 
    )

运行“paster setup-app development.ini”时,SQLAlchemey 将 FK 值报告为“None”,因此显然没有找到它:

15:24:27,284 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] 
CREATE TABLE authors (
    id SERIAL NOT NULL, 
    first_name VARCHAR(100), 
    last_name VARCHAR(100), 
    PRIMARY KEY (id)
)

15:24:27,284 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] {}
15:24:27,291 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] COMMIT
15:24:27,292 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] 
CREATE TABLE books (
    id SERIAL NOT NULL, 
    title VARCHAR(100), 
    author_id INTEGER, 
    PRIMARY KEY (id), 
    FOREIGN KEY(author_id) REFERENCES authors (id)
)

15:24:27,293 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] {}
15:24:27,300 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] COMMIT
15:24:27,301 INFO  [blog.websetup] Inserting initial data
15:24:27,302 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] BEGIN
15:24:27,309 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] INSERT INTO authors (first_name, last_name) VALUES (%(first_name)s, %(last_name)s) RETURNING authors.id
15:24:27,309 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] {'first_name': 'Frank', 'last_name': 'Herbert'}
15:24:27,320 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] INSERT INTO books (title, author_id) VALUES (%(title)s, %(author_id)s) RETURNING books.id
15:24:27,320 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] {'author_id': None, 'title': 'Dune'}
15:24:27,322 INFO  [sqlalchemy.engine.base.Engine.0x...9f50] COMMIT
15:24:27,323 INFO  [blog.websetup] Done

fixture 文档实际上警告这可能是个问题:

“但是,在某些情况下,您可能需要引用在加载之前没有值的属性,例如序列 ID 列。(请注意,使用会话时 SQLAlchemy 数据层不支持此功能。) "

http://farmdev.com/projects/fixture/using-dataset.html#referencing-foreign-dataset-classes

这是否意味着 SQLAlchemy 不支持此功能?或者是否可以在不使用 SA“会话”的情况下加载数据?其他人如何处理这个问题?

【问题讨论】:

    标签: python postgresql sqlalchemy pylons fixture


    【解决方案1】:

    SQLAlchemy 中的 SQL 表达式层不支持引用尚未插入的行,因为它没有意义:所有查询都是显式执行的。 ORM 层确实支持对新对象的引用,它甚至使用工作单元模式来正确组织插入顺序。为了解决这个问题,夹具使用ref() 方法。但请注意,在 SQL 表达式层中,您(夹具)执行语句,因此 SQLAlchemy 没有机会重新排序它们。所以author_id 不可用,如果您尝试在它所指的作者之前存储书籍。您确定您的固定装置按正确的顺序组织(传递给data() 方法)吗?

    【讨论】:

    • 是的 - 请参阅上面更新的 SA 日志。我什至尝试在完全独立的 data() 语句中插入 Authors 和 Books 数据……不走运
    【解决方案2】:

    你不能说author = AuthorsData.frank_herbert而不是直接指定author_id吗?

    除此之外,也许在插入您的 AuthorsData 后调用 meta.Session.flush() 会强制 id 属性获取值?当我需要分配 ID 时,这就是我在测试中使用的(我不使用固定装置)。

    【讨论】:

      【解决方案3】:

      我通过这样定义orm.relation 来解决这个问题:

      class BooksData(DataSet):
          class dune:
              title = "Dune"
              author = AuthorsData.frank_herbert
      
      
      mapper(Book, books, properties={
         'author': relation(Author)
       })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-10-01
        • 2021-01-01
        • 2015-02-02
        • 2017-08-20
        • 2012-02-29
        • 2015-04-07
        • 2013-10-11
        相关资源
        最近更新 更多