'AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with table

I have a problem concerning a form on association table in the form of a modal. I want to retrieve an id in backend, but SQLalchemy doesn't seem to recognize this join.

I'm sure it's probably a silly mistake on my part, but I've been stuck on it for some time.

Thanks in advance for your help

Class model

class Militer(db.Model):
    militer_id = db.Column(db.Integer, nullable=True, autoincrement=True, primary_key=True)
    acteur_id = db.Column(db.Integer, db.ForeignKey('acteur.id'))
    orga_id = db.Column(db.Integer, db.ForeignKey('orga.id'))
    date_debut = db.Column(db.Text)
    date_fin = db.Column(db.Text)
    statut = db.Column(db.Text)
    #Relations
    orga = db.relationship("Orga", back_populates="militer")
    acteur = db.relationship("Acteur", back_populates="militer")

    @staticmethod
    def ajout_militer(acteur_id, orga_id, date_debut, date_fin, statut):
        erreurs = []
        if not acteur_id:
            erreurs.append("Veuillez renseigner la personne.")
        if not orga_id:
            erreurs.append("Veuillez renseigner l'organisation'")

        unique = Militer.query.filter(db.and_(
            Militer.acteur.id == acteur_id,
            Militer.orga.id == orga_id
        )).count()
        if unique > 0:
            erreurs.append("Cette participation est déjà présente au sein de la base de données.")

            # S'il y a au moins une erreur, afficher un message d'erreur.
        if len(erreurs) > 0:
            return False, erreurs

            # Si aucune erreur n'a été détectée, ajout d'une nouvelle entrée dans la table Militer
        nouvelle_participation = Militer(acteur=acteur_id,
                                         orga=orga_id,
                                         date_debut=date_debut,
                                         date_fin=date_fin,
                                         statut=statut)

        try:
            db.session.add(nouvelle_participation)
            db.session.commit()
            return True, nouvelle_participation

        except Exception as erreur:
            return False, [str(erreur)]

associated tables

class Acteur(db.Model):
    id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
    nom = db.Column(db.Text, nullable=False)
    prenom = db.Column(db.Text, nullable=False)
    date_naissance = db.Column(db.Text, nullable=False)
    date_deces = db.Column(db.Text)
    ville_naissance = db.Column(db.Text, nullable=False)
    pays_naissance = db.Column(db.Integer, db.ForeignKey('pays.id'))
    profession = db.Column(db.Text)
    biographie = db.Column(db.Text, nullable=False)
    #Relations
    authorships = db.relationship("AuthorshipActeur", back_populates="acteur")
    participation = db.relationship("Participation", back_populates="acteur")
    militer = db.relationship("Militer", back_populates="acteur")
    pays = db.relationship("Pays", back_populates="acteur")

class Orga(db.Model):
    id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
    nom = db.Column(db.Text, nullable=False)
    pays_id = db.Column(db.Integer, db.ForeignKey('pays.id'))
    type_orga = db.Column(db.Text)
    date_fondation = db.Column(db.Text)
    description = db.Column(db.Text)
    #Relations
    militer = db.relationship("Militer", back_populates="orga")
    pays = db.relationship("Pays", back_populates="orga")
    authorships = db.relationship("Authorship_Orga", back_populates="orga")

Fonction add data in association table

@login_required
@app.route("/ajout_militer", methods=["GET", "POST"])
def militer():

    # Ajout d'une personne
    if request.method == "POST":
        statut, informations = Militer.ajout_militer(
            acteur_id=Acteur.query.get(request.form["acteur"]),
            orga_id=Orga.query.get(request.form["orga"]),
            date_debut=request.form.get("date_debut", None),
            date_fin=request.form.get("date_fin", None),
            statut=request.form.get("statut", None)
        )
        name_id = request.form.get("acteur")

        if statut is True:
            flash("Ajout d'une nouvelle participation à une organisation", "success")
            return redirect(url_for('militant', name_id=name_id))
        else:
            flash("L'ajout a échoué pour les raisons suivantes : " + ", ".join(informations), "danger")
            return None

Extract of origin route

@app.route("/militant/<int:name_id>")
def militant(name_id):
    #Requete SQL
    unique_militants = Acteur.query.get(name_id)
    "..."
    return render_template("pages/militant.html", militant=unique_militants, createur=createur, compte_organisation=compte_organisation,
                               organisation=organisation, participer=participer, compte_participer=compte_participer, liste_orga=liste_orga)

extract of templates

<div class="modal fade" id="militerModal" tabindex="-1">
          <div class="modal-dialog">
            <div class="modal-content">
              <form class="form" method="POST" action="{{url_for('militer')}}">
                  <div class="modal-header">
                    <h5 class="modal-title">Ajout d'une participation à une organisation</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                  </div>
                  <div class="modal-body">
                      <div><input type="hidden" name="acteur" value="{{militant.id}}"></div>
                      <div class="form-group row">
                          <label for="orga" class="col-sm-8 col-form-label">Organisation* <a href="{{url_for('inscription_orga')}}" style="font-size: small;">(Ajouter une organisation ?)</a></label>
                          <input class="form-control"  name="orga" list="datalistOrgaOptions" id="orga" placeholder="Rechercher..." required>
                          <datalist id="datalistOrgaOptions">
                              {% for groupe in liste_orga %}
                                        <option value="{{groupe.id}}" label="{{groupe.nom}}"></option>
                                    {% endfor %}
                          </datalist>
                      </div>
                      <div class="form-group row">
                        <label class="col-sm-2 col-form-label">Date de début</label>
                        <div class="col-sm-10">
                          <input type="text" class="form-control" name="date_debut" placeholder="..."/>
                        </div>
                      </div>

visual modal bootstrap visual modal bootstrap

error



Solution 1:[1]

fellow tnah,

i had the exact same problem earlier. you cannot use the db.relationship objects in filter / db.and_ queries. what you can do is bypass (contourner) this :

instead of doing Militer.acteur.id == acteur_id and Militer.orga.id == orga_id, you should try:

unique = Militer.query.filter(db.and_(
   Militer.acteur_id == acteur_id,
   Militer.orga_id == orga_id
)).count()

Solution 2:[2]

You can use the fk directly instead of trying to access the relationship.


class Militer:

    def ajout_militer(acteur_id, orga_id, date_debut, date_fin, statut):
        # Example 1: Directly reference the foreign keys on Militer
        unique = Militer.query.filter(db.and_(
            Militer.acteur_id == acteur_id,
            Militer.orga_id == orga_id
        )).count()
        #...

If you need to filter on a column using the relationship then you have to use join to bring those columns into the rows (see last example)


class Militer:

    def ajout_militer(acteur_id, orga_id, date_debut, date_fin, statut):
        # Example 2: Join to acteur using relationship to reference its id.
        unique = Militer.query.join(Militer.acteur).filter(
            Acteur.id == acteur_id,
        ).count()
        #...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 paulhector
Solution 2 Ian Wilson