web-dev-qa-db-fra.com

Impossible d'assembler des colonnes de clé primaire pour la table mappée

Lorsque j'essaie de créer une migration de schéma de base de données, j'obtiens cette erreur étrange. Pouvez-vous m'aider à comprendre ce qui ne va pas?

$ python app.py db upgrade
[skipped]
sqlalchemy.exc.ArgumentError: Mapper Mapper|EssayStateAssociations|essay_associations could not assemble any primary key columns for mapped table 'essay_associations'

Mon modèle:

class EssayStateAssociations(db.Model):
    __tablename__ = 'essay_associations'

    application_essay_id = db.Column(
        db.Integer,
        db.ForeignKey("application_essay.id"),
        primary_key=True),
    theme_essay_id = db.Column(
        db.Integer,
        db.ForeignKey("theme_essay.id"),
        primary_key=True),
    state = db.Column(db.String, default="pending")
39
Michael Samoylov

Vous ne pouvez pas avoir deux clés primaires dans une table. Au lieu de cela, vous devez utiliser une clé primaire composée. Cela peut être fait en ajoutant un PrimaryKeyConstraint dans votre modèle comme ci-dessous (n'oubliez pas d'ajouter une virgule avant de fermer le support dans __table_args__:

from db import PrimaryKeyConstraint

class EssayStateAssociations(db.Model):
    __tablename__ = 'essay_associations'
    __table_args__ = (
        PrimaryKeyConstraint('application_essay_id', 'theme_essay_id'),
    )

    application_essay_id = db.Column(
        db.Integer,
        db.ForeignKey("application_essay.id"))
    theme_essay_id = db.Column(
        db.Integer,
        db.ForeignKey("theme_essay.id"))
    state = db.Column(db.String, default="pending")
32
Minh Pham

Vous obtenez cette erreur car vous avez des virgules après vos définitions de Column(), ce qui fait que application_essay_id Et theme_essay_id Sont chacun analysés comme un tuple à un élément contenant un Column au lieu d'un Column. Cela empêche SQLAlchemy de "voir" que les colonnes sont présentes et, par conséquent, votre modèle ne contient aucune colonne de clé primaire.

Si vous remplacez simplement

application_essay_id = db.Column(
    db.Integer,
    db.ForeignKey("application_essay.id"),
    primary_key=True),
theme_essay_id = db.Column(
    db.Integer,
    db.ForeignKey("theme_essay.id"),
    primary_key=True),

avec

application_essay_id = db.Column(
    db.Integer,
    db.ForeignKey("application_essay.id"),
    primary_key=True)
theme_essay_id = db.Column(
    db.Integer,
    db.ForeignKey("theme_essay.id"),
    primary_key=True)

alors votre erreur sera corrigée.

En plus: puisque SQLAlchemy (et Alembic et Flask-SQLAlchemy) contiennent des syntaxes pour déclarer des modèles/tables qui impliquent de passer une séquence séparée par des virgules de Columns comme arguments (par exemple à op.create_table() ou Table() constructor) et d'autres qui impliquent de déclarer une classe avec Columns comme propriétés de classe, c'est vraiment facile de rencontrer cette erreur en coupant et collant Column déclarations de la première syntaxe à la seconde et oubliant de supprimer certaines virgules. Je soupçonne que cette erreur facile à faire est la raison pour laquelle cette question a un si grand nombre de vues - plus de 16 000 au moment où je poste cette réponse.

39
Mark Amery