web-dev-qa-db-fra.com

Flask-SQLAlchemy vérifie si une ligne existe dans la table

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.

23
Pav Sidhu

É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
35
davidism

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.

11
lyschoening
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.

2
Anna

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.

0
kblomqvist