SQLAlchemy serverseitige datetime Berechnungen
Warum Sie versuchen sollten, client-seitige datetime Berechnungen zu vermeiden, wenn Sie SQLAlchemy nicht....
Hier finden Sie viele SQLAlchemy datetime Berechnungsbeispiele, z.B. mit der timedelta Funktion 's. Warum? Ich verstehe das nicht, außer dass das einfach ist. Aber ist es richtig?
Angenommen, wir wollen alle Benutzerdatensätze oder Objekte, die vor zwei Stunden erstellt wurden und die Datensatz / Objektdefinition ist:
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)
Wenn Python wir dann die Datensätze / Objekte auswählen könnten, die in den letzten 10 Minuten hinzugefügt wurden, könnten wir so etwas wie Folgendes tun:
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()
Die generierte SQL ist:
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)}
Dies funktioniert nur, gibt valide Ergebnisse, wenn:
- der Datenbankserver läuft auf dem gleichen Server, auf dem auch der Python Code läuft.
- der Datenbankserver auf einem anderen Server als der Python Code-Server läuft und die Zeit auf beiden Servern perfekt synchronisiert ist.
Angenommen, Sie haben einen separaten Datenbankserver und die Zeit dieses Servers ist 2 Minuten außerhalb der Synchronisation. Dann erhalten Sie falsche, unvollständige Ergebnisse. Ich schreibe seit vielen Jahren serverseitige Anfragen und bin überrascht, dass es in SQLAlchemy Fragen und Antworten wenig Aufmerksamkeit dafür gibt.
Der einzige Weg, um die richtigen Ergebnisse zu erzielen, besteht darin, die datetime Stempel der Datensätze des Datenbankservers zu verwenden und sie zu addieren datetime oder davon abzuziehen datetime . Mit MariaDB / MySQL können Sie die Intervallanweisung verwenden:
SELECT user.* FROM user WHERE created_on > (NOW() - INTERVAL 2 HOUR)
Leider konnte ich keine Lösung finden, SQLAlchemy die für alle Datenbanken gültig wäre. SQLAlchemy Hat das text() Objekt, übergibt es den Wert an die Abfrage. Mit text()wird die SQLAlchemy Abfrage zu:
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()
Die generierte SQL ist:
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
Beachten Sie, dass diese Abfrage möglicherweise nicht auf allen Datenbanksystemen funktioniert. Es funktioniert mit MariaDB / MySQL aber es funktioniert sicherlich nicht mit SQLite.
Wenn Sie eine Anwendung entwickeln und alles auf einem Computer laufen lassen, dann denken Sie immer daran, dass Sie die Datenbank in Zukunft vielleicht auf einem separaten Server betreiben möchten. Es ist also keine schlechte Idee, Ihre Anfragen für diese Situation zu entwickeln.
Links / Impressum
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
Mehr erfahren
SQLAlchemy
Einen Kommentar hinterlassen
Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.
Kommentare (5)
Eine Antwort hinterlassen
Antworten Sie anonym oder melden Sie sich an, um zu antworten.
Another great post. I have to agree it is surprising most solutions on the web ignore the potential Python app versus DBMS clock difference problem. The kind of bug that waits patiently until its time!
FWIW `sqlalchemy.sql.expression.func.now() - timedelta(minutes=2)` seems to work for Postgres and I would expect others with a NOW() function.
I just noticed the post above immediately displayed as posted 1 hour ago . . . I'm on GMT (London).
Me again! But after posting the second post, the first changed to "2 minutes ago", the second started at "0 seconds ago"!
Then after the third post all three now say "1 hour" . . . had to wait 5 minutes to post this one :-)
Thank you for reporting this. I am still working on many parts of this website ... will fix this soon.
Neueste
- Ausblenden der Primärschlüssel der Datenbank UUID Ihrer Webanwendung
- Don't Repeat Yourself (DRY) mit Jinja2
- SQLAlchemy, PostgreSQL, maximale Anzahl von Zeilen pro user
- Anzeige der Werte in den dynamischen Filtern SQLAlchemy
- Sichere Datenübertragung mit Public Key Verschlüsselung und pyNaCl
- rqlite: eine hochverfügbare und distverteilte SQLite -Alternative
Meistgesehen
- Verwendung von Pythons pyOpenSSL zur Überprüfung von SSL-Zertifikaten, die von einem Host heruntergeladen wurden
- Verwendung von UUIDs anstelle von Integer Autoincrement Primary Keys mit SQLAlchemy und MariaDb
- PyInstaller und Cython verwenden, um eine ausführbare Python-Datei zu erstellen
- Verbindung zu einem Dienst auf einem Docker -Host von einem Docker -Container aus
- SQLAlchemy: Verwendung von Cascade Deletes zum Löschen verwandter Objekte
- Flask RESTful API Validierung von Anfrageparametern mit Marshmallow-Schemas