J'ai une application Flask qui utilise Flask-SQLAlchemy pour se connecter à une base de données MySQL.
Je voudrais pouvoir vérifier si une ligne est présente dans un tableau. Comment pourrais-je modifier une requête comme ça pour vérifier que la ligne existe:
db.session.query(User).filter_by(name='John Smith')
J'ai trouvé une solution sur cette question qui utilise SQLAlchemy mais ne semble pas correspondre à la façon dont Flask-SQLAlchemy fonctionne:
from sqlalchemy.sql import exists
print session.query(exists().where(User.email == '...')).scalar()
Merci.
Étant donné que vous souhaitez uniquement voir si l'utilisateur existe, vous ne souhaitez pas interroger l'intégralité de l'objet. Recherchez simplement l'id, il existe si le retour scalaire n'est pas None.
exists = db.session.query(User.id).filter_by(name='davidism').scalar() is not None
SELECT user.id AS user_id
FROM user
WHERE user.name = ?
La deuxième requête que vous avez montrée fonctionne également correctement, Flask-SQLAlchemy ne fait rien pour empêcher tout type de requête que SQLAlchemy peut effectuer. Cela renvoie False
ou True
au lieu de None
ou un identifiant comme ci-dessus, mais il est légèrement plus cher car il utilise une sous-requête.
exists = db.session.query(db.exists().where(User.name == 'davidism')).scalar()
SELECT EXISTS (SELECT *
FROM user
WHERE user.name = ?) AS anon_1
Enveloppez une requête .exists()
dans une autre session.query()
avec un appel scalar()
à la fin. SQLAlchemy produira une requête EXISTS
optimisée qui renvoie True
ou False
.
exists = db.session.query(
db.session.query(User).filter_by(name='John Smith').exists()
).scalar()
SELECT EXISTS (SELECT 1
FROM user
WHERE user.name = ?) AS anon_1
Bien qu'il soit potentiellement plus cher en raison de la sous-requête, il est plus clair de savoir ce qui est interrogé. Il peut également être préférable à db.exists().where(...)
car il sélectionne une constante au lieu de la ligne complète.
bool(User.query.filter_by(name='John Smith').first())
Il renverra "False" si les objets de ce nom n'existent pas et "True" s'il existe.
Pardonnez le détournement mais ... avec les instructions données ici, j'ai fait le validateur WTForm suivant pour vérifier l'unicité du champ
class Unique(object):
def __init__(self, column, session, message="Already exists."):
self.column = column
self.session = session
self.message = message
def __call__(self, form, field):
if field.data == field.object_data:
return # Field value equals to existing value. That's ok.
model = self.column.class_
query = model.query.filter(self.column == field.data).exists()
if self.session.query(query).scalar():
raise ValidationError(self.message)
Il serait utilisé comme ceci
class Register(Form):
email = EmailField('Email', [Unique(User.email, db.session)])
Cependant, je voudrais avoir une API qui n'a pas besoin de session db comme deuxième paramètre
class Register(Form):
email = EmailField('Email', [Unique(User.email)])
Existe-t-il un moyen d'obtenir une session db à partir du modèle? Sans session, il semble impossible d'éviter de charger l'intégralité de l'objet pour vérifier son existence.