2016-02-12 5 views
0

Я пытаюсь преобразовать старый код sqlite3 в sql alchemy. Я пытаюсь понять, как лучше всего использовать мой прецедент. Я новичок в методе доступа к базе данных ORM.динамические имена таблиц с SQLalchemy

Я пытаюсь динамически генерировать уникальные имена таблиц на основе общего определения. Я прочитал mixins guide, а также сообщение о том, как использовать typeto dynamically declare classes, но я до сих пор не уверен, как бы я это сделал. Вот то, что я до сих пор:

from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey 
from sqlalchemy.ext.declarative import declared_attr 

Base = declarative_base() 


class DynamicName(object): 
    @declared_attr 
    def __tablename__(cls): 
     return cls.__name__.lower() 

class Genome(DynamicName, Base): 
    __tablename__ = 'AbstractGenome' 
    AlignmentId = Column(Integer, primary_key=True) 
    StartOutOfFrame = Column(Integer) 
    BadFrame = Column(Integer) 

def build_genome_table(genome): 
    d = {'__tablename__': genome} 
    table = type(genome, (Genome,), d) 
    return table 

Если я пытаюсь использовать это, он не работает:

>>> from sqlalchemy import create_engine 
>>> engine = create_engine('sqlite:///:memory:', echo=True) 
>>> genomes = ["A", "B"] 
>>> tables = {x: build_genome_table(x) for x in genomes} 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 1, in <dictcomp> 
    File "<stdin>", line 3, in build_genome_table 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 55, in __init__ 
    _as_declarative(cls, classname, cls.__dict__) 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 88, in _as_declarative 
    _MapperConfig.setup_mapping(cls, classname, dict_) 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 103, in setup_mapping 
    cfg_cls(cls_, classname, dict_) 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 135, in __init__ 
    self._early_mapping() 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 138, in _early_mapping 
    self.map() 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 529, in map 
    **self.mapper_args 
    File "<string>", line 2, in mapper 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 623, in __init__ 
    self._configure_inheritance() 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 930, in _configure_inheritance 
    self.local_table) 
    File "<string>", line 2, in join_condition 
    File "/cluster/home/ifiddes/python2.7/lib/python2.7/site-packages/sqlalchemy/sql/selectable.py", line 839, in _join_condition 
    (a.description, b.description, hint)) 
sqlalchemy.exc.NoForeignKeysError: Can't find any foreign key relationships between 'AbstractGenome' and 'A'. 

Как я могу идти о динамически генерировать Genome таблицу на основе прошедшего имени ? Мне также идеально понравилась бы установка, в которой у меня может быть иерархическое наследование, чтобы я мог объявлять разные подклассы, например ReferenceGenome или TargetGenome, которые имеют дополнительные столбцы, но также могут иметь динамические имена.

+1

SQLAlchemy пытается настроить наследование и сбой, поскольку у вас нет внешнего ключа между таблицей 'A' и' AbstractGenome'. Действительно ли вы намереваетесь создать как таблицу 'A', так и таблицу AbstractGenome? Если нет, вы должны поместить '__abstract__ = True' в определение' class Genome'. – univerio

ответ

1

См.: sqlalchemy.orm.mapper: http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html#class-mapping-api. Мое понимание (поскольку в прошлом я только модифицировал код с использованием этой функции) заключается в том, что он непосредственно сопоставляет модельный класс с объектом таблицы, который сам связан с таблицей базы данных.

Этот прецедент на самом деле очень похож на рецепт history_meta: http://docs.sqlalchemy.org/en/latest/_modules/examples/versioned_history/history_meta.html. Это может занять некоторое время, но объект таблицы создается здесь динамически на основе существующей модели (любой подкласс версии Versioned), а затем непосредственно сопоставляется с таблицей базы данных при создании класса.

Вот проблема: вам нужна фактическая таблица базы данных для сопоставления. Это ORM в конце концов. У вас есть несколько вариантов здесь:

  1. Если вы хотите создать таблицу на лету, которые будут сохраняться в базе данных, вы можете использовать Table.create(), как в здесь: http://docs.sqlalchemy.org/en/latest/core/metadata.html#creating-and-dropping-database-tables

  2. Если вам нужно всего лишь создавать таблицы время от времени, вы можете интегрировать их с alembic: https://pypi.python.org/pypi/alembic

  3. Если вам это нужно только для одного процесса, и никогда больше нет, вы можете создавать временные таблицы, хотя я не уверен, что SQLAlchemy напрямую поддерживает его. Кажется, что несколько ресурсов, которые я проверил, используют create() и drop(). Я не использовал SQLAlchemy 1.0+, поэтому он может иметь некоторую поддержку где-то, чего я не видел.

Сообщите мне, если что-то здесь неясно. Прошло некоторое время с тех пор, как я играл с history_meta.py, поэтому я могу быть ржавым.

Смежные вопросы