Sqlalchemy e campi calcolati

Come definire con sqlalchemy dei campi calcolati da utilizzare nelle nostre query come fossero dei normali campi definiti sulla tabella nel db relazionale

Tanto per cambiare ho un problema da risolvere... ho una tabella su un database postgesql che registra in due campi differenti la data e l'ora. Questa situazione non è delle migliori e non mi permette di filtrare i dati nel modo che mi aspetto. Purtroppo non posso modificare la struttura del database quindi devo trovare una soluzione alternativa.

La mia tabella su db relazionale è composta più o meno così:

  • id - identificativo numerico progressivo del record
  • data - campo di tipo date nella che registra l'anno, il mese ed il giorno
  • ora - campo di tipo time che registra l'ora, i minuti ed i secondi

La tabella viene mappata in un modello di sqlalchemy in modo dichiarativo in questo modo:

from sqlalchemy import Column, Integer, Date, Time, DateTime, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Model(Base):
__tablename__ = 'modello'
id = Column(Integer, primary_key=True)
data = Column(Date)
ora = Column(Time)

Con un modello così definito posso interrogare il database filtrando i dati per id, data e ora ma ho anche l'esigenza di filtrare per data e ora insieme e non voglio complicare oltremodo le query. Nel mio caso specifico devo filtrare periodicamente i record delle ultime 4 ore ed interrogare il database tra la mezanotte e le quattro di mattina potrebbe essere un problema.

Mi farebbe molto comodo un campo datetime ma non potendo modificare la struttura della tabella devo trovare una soluzione con sqlalchemy.

Con sqlalchemy posso mappare un campo calcolato attraverso il quale restituire un datetime partendo dai valori dei campi esistenti. In postgresql il campo calcolato lo definirei in questo modo (magari non è molto bello ma funziona):

cast(cast(data as TEXT)||' '|| cast(ora as TEXT) AS TIMESTAMP)

e con sqlalchemy posso ricreare una proprietà simile in questo modo:

from sqlalchemy.sql.expression import cast
from sqlalchemy.util import classproperty from sqlalchemy.orm import column_property
...
class Model(Base):
...
@classproperty
def data_ora(cls):
data = cast(cls.data, String)
ora = cast(cls.ora, String)
return column_property(cast(data + ' ' + ora, DateTime))

nota: nel metodo 'data_ora' viene usata la varibile cls al posto di self in quanto è un classmethod cfr. docs.python e pep8

adesso posso filtrare i record delle ultime 4 ore in modo semplice:

from datetime import datetime, timedelta
adesso = datetime.now()
quattro_ore_fa = adesso - timedelta(hours = 4)
sqlalchemy_session.query(Model).filter(Model.data_ora >= quattro_ore_fa)

Per maggiori informazioni

Share this on

Share |

On same topics

Commenti

comments powered by Disqus