Domanda

Ho un database già esistente e voglio accedervi usando SQLAlchemy. Perché, la struttura del database è gestita da un altro pezzo di codice (Django ORM, in realtà) e non voglio ripetermi, descrivendo ogni struttura di tabella, sto usando l'introspezione autoload . Sono bloccato con una semplice eredità di tabella concreta.

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

Ecco il codice, con le descrizioni delle tabelle SQL come 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}

Le tabelle effettive hanno colonne aggiuntive, ma questo è del tutto irrilevante per la domanda, quindi nel tentativo di ridurre al minimo il codice ho semplificato tutto solo al centro.

Il problema è che quando eseguo questo:

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

L'SQL risultante è insignificante (notare la mancanza della condizione di join):

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 provo ad accedere a payment.date ricevo il seguente errore: Concrete Mapper | FooPayment | payment_foo non implementa l'attributo u'date 'a livello di istanza.

Ho provato ad aggiungere il riferimento implicito alla chiave esterna id = Column ('payment_ptr_id', Integer, ForeignKey ('payment_payment.id'), primary_key = True) in FooPayment senza successo. Provare print session.query (Payment) .first (). User funziona (ho omesso la classe User e commentato la riga perfettamente), quindi l'introspezione FK funziona.

Come posso eseguire una semplice query su FooPayment e accedere ai valori di Payment dall'istanza risultante?

Sto usando SQLAlchemy 0.5.3, PostgreSQL 8.3, psycopg2 e Python 2.5.2. Grazie per eventuali suggerimenti.

È stato utile?

Soluzione

Le strutture della tabella sono simili a quelle utilizzate nell'ereditarietà delle tabelle comuni, ma certamente non corrispondono all'ereditarietà delle tabelle concrete in cui tutti i campi della classe genitore sono duplicati nella tabella della sottoclasse. In questo momento hai una sottoclasse con meno campi rispetto a parent e un riferimento all'istanza della classe parent. Passa all'eredità della tabella congiunta (e usa FooPayment.amount nelle tue condizioni o rinuncia all'eredità a favore di una semplice aggregazione (riferimento).

Il filtro per campo in un altro modello non aggiunge automaticamente la condizione di join. Sebbene sia ovvio quale condizione dovrebbe essere utilizzata in join per il tuo esempio, non è possibile determinare tale condizione in generale. Ecco perché devi definire la proprietà della relazione facendo riferimento a Pagamento e utilizzare il suo metodo has () nel filtro per ottenere la condizione di join corretta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top