Pergunta

Eu tenho um banco de dados já existente e quer acessá-lo usando SQLAlchemy. Porque, a estrutura de banco de dados é gerenciado por outro pedaço de código (Django ORM, na verdade) e eu não quero me repetir, descrevendo cada estrutura de tabela, eu estou usando autoload introspecção. Eu estou preso com uma herança concreta de tabelas simples.

Payment                FooPayment
  + id (PK) <----FK------+ payment_ptr_id (PK)
  + user_id              + foo
  + amount
  + date

Aqui está o código, com descritions SQL tabela como docstrings:

class Payment(Base):
    """
    CREATE TABLE payments(
      id serial NOT NULL,
      user_id integer NOT NULL,
      amount numeric(11,2) NOT NULL,
      date timestamp with time zone NOT NULL,
      CONSTRAINT payment_pkey PRIMARY KEY (id),
      CONSTRAINT payment_user_id_fkey FOREIGN KEY (user_id)
          REFERENCES users (id) MATCH SIMPLE)
    """
    __tablename__ = 'payments'
    __table_args__ = {'autoload': True}
    # user = relation(User)

class FooPayment(Payment):
    """
    CREATE TABLE payments_foo(
      payment_ptr_id integer NOT NULL,
      foo integer NOT NULL,
      CONSTRAINT payments_foo_pkey PRIMARY KEY (payment_ptr_id),
      CONSTRAINT payments_foo_payment_ptr_id_fkey
          FOREIGN KEY (payment_ptr_id)
          REFERENCES payments (id) MATCH SIMPLE)
    """
    __tablename__ = 'payments_foo'
    __table_args__ = {'autoload': True}
    __mapper_args__ = {'concrete': True}

As tabelas reais têm colunas adicionais, mas isso é completamente irrelevante para a questão, portanto, em tentativa de minimizar o código que eu simplificado tudo apenas para o núcleo.

O problema é, quando eu executar este:

payment = session.query(FooPayment).filter(Payment.amount >= 200.0).first()
print payment.date

O SQL resultante é sem sentido (note a falta de se juntar condidion):

SELECT payments_foo.payment_ptr_id AS payments_foo_payment_ptr_id,
       ... /* More `payments_foo' columns and NO columns from `payments' */
    FROM payments_foo, payments
    WHERE payments.amount >= 200.0 LIMIT 1 OFFSET 0

E quando eu estou tentando acessar payment.date eu recebo o seguinte erro: Concrete Mapper|FooPayment|payments_foo does not implement attribute u'date' at the instance level.

Eu tentei adicionar implícita id = Column('payment_ptr_id', Integer, ForeignKey('payments_payment.id'), primary_key=True) referência de chave estrangeira para FooPayment sem qualquer sucesso. Tentando obras print session.query(Payment).first().user (eu omitido classe User e comentou a linha) perfeitamente, então obras de introspecção FK.

Como posso executar uma consulta simples em valores FooPayment e acesso de Payment partir resultando exemplo?

Eu estou usando SQLAlchemy 0.5.3, PostgreSQL 8.3, psycopg2 e Python 2.5.2. Obrigado por todas as sugestões.

Foi útil?

Solução

As suas estruturas de tabela são semelhantes ao que é usado na herança de tabela conjunta, mas eles certamente não correspondem à herança concreta de tabelas onde todos os campos da classe pai são duplicados na tabela de subclasse. Agora você tem uma subclasse com menos campos do que pai e uma referência a instância de classe pai. Mudar para a herança conjunta mesa (e uso FooPayment.amount em sua condição ou desistir com a herança em favor da agregação simples (de referência).

Filtrar por um campo em outro modelo não adiciona automaticamente condição de junção. Embora seja óbvio que condição deve ser usado em juntar-se para o seu exemplo, não é possível determinar tal condição em geral. É por isso que você tem que definir a propriedade relação referindo-se a pagamento e usar seu método has() no filtro para obter adequada condição de junção.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top