Импортировать светильники с внешними ключами и SQLAlchemy? - PullRequest
3 голосов
/ 03 июня 2010

Я экспериментировал с использованием прибора для загрузки наборов тестовых данных в мое приложение Pylons / PostgreSQL. Это прекрасно работает, за исключением того, что он не может правильно создать внешние ключи, если они ссылаются на поле идентификатора автоматического увеличения.

Мой прибор выглядит так:

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 как "Нет", поэтому он явно не находит его:

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

Документы о приборах фактически предупреждают, что это может быть проблемой:

"Однако в некоторых случаях может потребоваться ссылка на атрибут, который не имеет значения до его загрузки, например столбец с серийным идентификатором. (Обратите внимание, что это не поддерживается уровнем данных SQLAlchemy при использовании сеансов.) «

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

Значит ли это, что это просто не поддерживается SQLAlchemy? Или возможно загрузить данные без использования SA "сессий"? Как другие люди решают эту проблему?

Ответы [ 3 ]

1 голос
/ 08 июля 2010

Разве вы не можете сказать author = AuthorsData.frank_herbert вместо указания author_id напрямую?

Кроме этого, возможно, вызов meta.Session.flush() после вставки вашего AuthorsData заставит атрибут id получить значение? Это то, что я использую в своих тестах, когда мне нужно назначить идентификатор (я не использую прибор).

1 голос
/ 03 июня 2010

Ссылка на еще не вставленные строки не поддерживается слоем выражений SQL в SQLAlchemy, потому что это бессмысленно: все запросы выполняются явно. Слой ORM поддерживает ссылки на новые объекты, он даже использует шаблон единицы работы для правильной организации порядка вставки. Для решения этой проблемы в приборе используется метод ref(). Но обратите внимание, что на уровне выражений SQL вы (фиксатор) выполняете операторы, поэтому у SQLAlchemy нет шансов изменить их порядок. Таким образом, author_id недоступен, если вы пытаетесь сохранить книгу до того, к какому автору она относится. Вы уверены, что ваши приборы организованы (переданы методу data()) в правильном порядке?

0 голосов
/ 21 июля 2011

Я решаю эту проблему, определяя orm.relation так:

class BooksData(DataSet):
    class dune:
        title = "Dune"
        author = AuthorsData.frank_herbert


mapper(Book, books, properties={
   'author': relation(Author)
 })
...