'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


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 |
