Question

J'ai déjà une base de données existante et je souhaite y accéder à l'aide de SQLAlchemy. Parce que la structure de la base de données est gérée par un autre morceau de code (Django ORM, en fait) et que je ne veux pas me répéter, décrivant chaque structure de table, j'utilise l'introspection autoload . Je suis coincé avec un simple héritage de table en béton.

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

Voici le code, avec la table SQL décrite comme 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}

Les tables réelles ont des colonnes supplémentaires, mais cela n’a absolument rien à voir avec la question. Par conséquent, pour tenter de minimiser le code, j’ai tout simplifié jusqu’au coeur.

Le problème est que, quand j'exécute ceci:

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

Le code SQL résultant n'a pas de sens (notez l'absence de condition de jointure):

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

Et lorsque j'essaie d'accéder à payment.date , l'erreur suivante apparaît: Le mappeur concret | FooPayment | payments_foo n'implémente pas l'attribut u'date 'au niveau de l'instance.

J'ai essayé d'ajouter une référence de clé étrangère implicite id = Column ('payment_ptr_id', Integer, ForeignKey ('payments_payment.id'), primary_key = True) à FooPayment sans succès. Essayer print session.query (Payment) .first (). User fonctionne (j'ai omis de classer la classe User et commenté la ligne), de sorte que l'introspection FK fonctionne.

Comment puis-je effectuer une requête simple sur FooPayment et accéder aux valeurs de Paiement à partir de l'instance résultante?

J'utilise SQLAlchemy 0.5.3, PostgreSQL 8.3, psycopg2 et Python 2.5.2. Merci pour vos suggestions.

Était-ce utile?

La solution

Vos structures de table sont similaires à celles utilisées dans l'héritage de table jointe, mais elles ne correspondent certainement pas à l'héritage de table concret dans lequel tous les champs de la classe parent sont dupliqués dans la table de la sous-classe. À l'heure actuelle, vous avez une sous-classe avec moins de champs que parent et une référence à une instance de classe parente. Passez à l'héritage de table jointe (et utilisez FooPayment.amount dans votre condition ou renoncez à l'héritage en faveur d'une agrégation simple (référence).

Le filtrage par champ d'un autre modèle n'ajoute pas automatiquement la condition de jointure. Bien qu'il soit évident quelle condition doit être utilisée dans join pour votre exemple, il n'est pas possible de déterminer une telle condition en général. C’est pourquoi vous devez définir la propriété de relation faisant référence à Paiement et utiliser sa méthode has () dans filter pour obtenir la condition de jointure appropriée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top