Pregunta

Tengo una base de datos ya existente y quiero acceder a ella usando SQLAlchemy. Porque, la estructura de la base de datos está administrada por otro código (Django ORM, en realidad) y no quiero repetirme, describiendo cada estructura de tabla, estoy usando la introspección autoload . Estoy atrapado con una simple herencia de tabla concreta.

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

Aquí está el código, con descripciones de tabla SQL 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}

Las tablas reales tienen columnas adicionales, pero esto es completamente irrelevante para la pregunta, por lo que en un intento por minimizar el código, he simplificado todo hasta el núcleo.

El problema es, cuando ejecuto esto:

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

El SQL resultante no tiene sentido (tenga en cuenta la falta de condiciones de unión):

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

Y cuando intento acceder a payment.date me sale el siguiente error: Concrete Mapper | FooPayment | pagos_foo no implementa el atributo u'date 'en el nivel de instancia.

He intentado agregar la referencia implícita de clave externa id = Column ('payment_ptr_id', Integer, ForeignKey ('payment_payment.id'), primary_key = True) a FooPayment sin ningún éxito. Intentar con print session.query (Payment) .first (). User funciona (he omitido la clase User y he comentado la línea) perfectamente, por lo que funciona la introspección FK.

¿Cómo puedo realizar una consulta simple en FooPayment y acceder a los valores de Payment desde la instancia resultante?

Estoy usando SQLAlchemy 0.5.3, PostgreSQL 8.3, psycopg2 y Python 2.5.2. Gracias por cualquier sugerencia.

¿Fue útil?

Solución

Las estructuras de su tabla son similares a las que se usan en la herencia de la tabla conjunta, pero ciertamente no corresponden a la herencia de la tabla concreta donde todos los campos de la clase padre se duplican en la tabla de la subclase. En este momento tiene una subclase con menos campos que el padre y una referencia a la instancia de la clase padre. Cambie a herencia de tabla conjunta (y use FooPayment.amount en su condición o renuncie a la herencia en favor de la agregación simple (referencia).

Filtrar por un campo en otro modelo no agrega automáticamente la condición de unión. Aunque es obvio qué condición debe usarse en join para su ejemplo, no es posible determinar dicha condición en general. Es por eso que debe definir la propiedad de relación que se refiere al Pago y utilizar su método has () en el filtro para obtener la condición de unión adecuada.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top