angle-up arrow-clockwise arrow-counterclockwise arrow-down-up arrow-left at calendar card-list chat check envelope folder house info-circle pencil people person person-plus phone plus question-circle search tag trash x

SQLAlchemy calculs côté serveur datetime

24 juin 2019 à côté de Peter
Dans SQLAlchemy

Pourquoi vous devriez essayer d'éviter les datetime calculs côté client à SQLAlchemy moins que...

post main image
Original photo unsplash.com/@nputra.

Vous trouverez de nombreux exemples de SQLAlchemy datetime calcul utilisant par exemple la timedelta fonction s. PythonPourquoi ? Je ne comprends pas cela, sauf que c'est facile. Mais est-ce correct ?

Supposons que nous voulons que tous les enregistrements utilisateur ou objets créés il y a deux heures et la définition de l'enregistrement / objet est :

class User(Base):

    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    created_on = Column(DateTime, server_default=func.now(), index=True)
    email = Column(String(100), server_default='', index=True)

Ensuite, si nous pouvions utiliser Python pour sélectionner les enregistrements / objets ajoutés au cours des 10 dernières minutes, nous pourrions faire quelque chose comme ceci :

from datetime import datetime, timedelta

now = datetime.now()
two_hours_ago = now - timedelta(hours=2)

# return all users created less then 2 hours ago
db.query(User).filter(User.created_on > two_hours_ago).all()

Le généré est :

SELECT user.id AS user_id, user.created_on AS user_created_on, user.email AS user_email
FROM user 
WHERE user.created_on > %(created_on_1)s
INFO sqlalchemy.engine.base.Engine {'created_on_1': datetime.datetime(2019, 6, 25, 7, 31, 58, 630959)}

Cela ne fonctionne, donne des résultats valides que si :

  • le serveur de la base de données est exécuté sur le même serveur que celui sur lequel le Python code est exécuté
  • le serveur de base de données fonctionne sur un serveur différent du serveur de Python code et le temps sur les deux serveurs est parfaitement synchronisé.

Supposons que vous avez un serveur de base de données séparé et que le temps de ce serveur est de 2 minutes désynchronisé. Alors vous vous trompez, les résultats sont incomplets. J'écris des requêtes côté serveur depuis de nombreuses années et je suis surpris qu'il y ait peu d'attention pour cela dans les SQLAlchemy questions et réponses.

La seule façon d'obtenir les bons résultats est d'utiliser les datetime timbres des enregistrements du serveur de base de données et d'y ajouter datetime ou d'en soustraire datetime des données. Avec MariaDB / MySQL vous pouvez utiliser l'instruction d'intervalle :

SELECT user.* FROM user WHERE created_on > (NOW() - INTERVAL 2 HOUR)

Malheureusement, je n'ai pas pu trouver une solution SQLAlchemy qui serait valable pour toutes les bases de données. SQLAlchemy a l' text() objet, il passe la valeur à la requête. Avec text(), la SQLAlchemy requête devient :

from sqlalchemy import text

two_hours_ago = text('NOW() - INTERVAL 2 HOURS')

# return all users created less then 2 hours ago
db.query(User).filter(User.created_on > two_hours_ago).all()

Le généré est :

SELECT user.id AS user_id, user.created_on AS user_created_on, user.email AS user_email
FROM user 
WHERE user.created_on > NOW() - INTERVAL 2 HOUR

Sachez que cette requête peut ne pas fonctionner sur tous les systèmes de base de données. Il fonctionne avec MariaDB / MySQL mais il ne fonctionne certainement pas avec SQLite.

Si vous développez une application et exécutez tout sur un seul ordinateur, gardez toujours à l'esprit qu'à l'avenir vous voudrez peut-être exécuter la base de données sur un serveur séparé. Ce n'est donc pas une mauvaise idée de développer vos requêtes pour cette situation.

Liens / crédits

Flask-sqlalchemy query datetime intervals
https://stackoverflow.com/questions/30495935/flask-sqlalchemy-query-datetime-intervals

SQLAlchemy datetime operations on server side
https://stackoverflow.com/questions/12540175/sqlalchemy-datetime-operations-on-server-side

SQLAlchemy default DateTime
https://stackoverflow.com/questions/13370317/sqlalchemy-default-datetime

Using DATEADD in sqlalchemy
https://stackoverflow.com/questions/15572292/using-dateadd-in-sqlalchemy/15573750#15573750

En savoir plus...:
SQLAlchemy

Laissez un commentaire

Commentez anonymement ou connectez-vous pour commenter.

Commentaires

Laissez une réponse

Répondez de manière anonyme ou connectez-vous pour répondre.