SQLAlchemy Order joined table by field in another joined table - python-3.x

My project requires that Orders are split into their individual lines which can be displayed in their own views I want these views to order the lines by eta which is a value in the Order table.
I have 3 tables with a 1>1 join on tables 1&2 and a many>many join on tables 2 and 3 defined by table 4 as follows:
class Order(db.Model):
id = db.Column(db.Integer, primary_key=True)
eta = db.Column(db.DateTime())
order_lines = db.relationship('Line', backref='order', order_by=lambda: Line.id)
def __repr__(self):
return '<Order No. {}>'.format(self.increment_id)
class Line(db.Model):
id = db.Column(db.Integer, primary_key=True)
line_name = db.Column(db.String())
order_id = db.Column(db.Integer, db.ForeignKey('order.id'))
product_id = db.Column(db.String, db.ForeignKey('product.product_id'))
def __repr__(self):
return '<Line SKU: {}>'.format(self.line_sku)
class Line_view(db.Model):
id = db.Column(db.Integer, primary_key=True)
view_name = db.Column(db.String())
view_lines = relationship('Line',
secondary='line_view_join',
backref='views',
lazy='dynamic',
order_by= ***???*** ) #ordery by eta on Order table
def __repr__(self):
return '<View: {}>'.format(self.view_name)
class Line_view_join(db.Model):
__tablename__ = 'line_view_join'
id = db.Column(db.Integer(), primary_key=True)
line_id = db.Column(db.Integer(), db.ForeignKey('line.id', ondelete='CASCADE'))
view_id = db.Column(db.Integer(), db.ForeignKey('line_view.id', ondelete='CASCADE'))
I am trying to work out how to query table 3, Line_View and have the joined Lines ordered by the eta of Order table.
Such that when querying:
chosen_view = Line_view.query.filter_by(id = 1).one()
chosen_view.view_lines are ordered by Order.eta
I have Tried
class Line_view(db.Model):
id = db.Column(db.Integer, primary_key=True)
view_name = db.Column(db.String())
view_lines = relationship('Line',
secondary='line_view_join',
backref='views',
lazy='dynamic',
**order_by=lambda: asc(Line.order.eta))**
def __repr__(self):
return '<View: {}>'.format(self.view_name)
But this results in the error:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Line.order has an attribute 'eta'

Do you need to store the Line_views in the database? If not, you can query the Lines sorted by the eta attribute of the related order. Below, I create two orders with one line each, and then query the lines sorted by the eta attribute of their order:
eta = datetime(2019,10,10)
o = Order(eta = eta)
l = Line(order=o, line_name="sample")
db.session.add(o)
db.session.add(l)
eta = datetime(2019,11,11)
o1 = Order(eta = eta)
l1 = Line(order=o1, line_name="sample1")
db.session.add(o1)
db.session.add(l1)
db.session.commit()
lines = Line.query.join(Order).order_by(Order.eta)

Related

Index a relationship in SQLAlchemy and Almbic

I have two tables like bellow:
Table 1:
class Table1(Base):
__tablename__ = "table1"
id = Column(UUID, primary_key=True)
created_at = Column(DateTime(True), nullable=False, server_default=func.now())
status_id = Column(ForeignKey("lookups.id"), index=True)
status = relationship(
"Lookup",
primaryjoin="Tables.status_id == Lookup.id",
backref="table1_statuses",
)
Table 2:
class Lookup(Base):
__tablename__ = "lookups"
id = Column(UUID, primary_key=True)
type = Column(String(64))
value = Column(String(256))
maximum = Column(Float(53), server_default="0")
sys_period = Column(TSTZRANGE, nullable=False, index=True)
HOW CAN I do a full text search on Table1 and find the status value. My query will look like this:
model = Table1
# search_term is `value` in the Lookup table
result = (session.query(model)
.filter(model.__ts_vector__.match(search_term)).all)

SQLalchemy query not updating relationship columns in put api

I have a model.py with a class Histogram and a table histogram_axes -
histograms_axes = Table(
"histograms_axes",
_ORMBase.metadata,
Column("histogram_id", ForeignKey("histograms.id"), primary_key=True),
Column("axis_id", ForeignKey("axes.id"), primary_key=True),
)
class Histogram(Base):
block = Column(Integer)
num = Column(Integer)
id = Column(Integer, ForeignKey("s.id"))
axes = relationship(
"Axis", secondary=histograms_axes, backref="histograms", order_by="asc(Axis.name)"
)
I have written a put API in FastAPI to update the rows based on id, but it only updates the columns not the relationship in Histogram class.
#router.put("/histograms")
def put_histograms(response: HistogramSchema, id: int, axes: List[int], db: Session = Depends(get_db)):
histogram = db.query(Histogram).filter(Histogram.id == id)
if not histogram.first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Histogram id {id} is not found!")
histogram.axes = db.query(Axis).filter(Axis.id.in_(axes)).all()
response = response.dict(exclude_unset=True)
histogram.update(response)
db.commit()
return histogram.one_or_none()
How can I update the relationship table as well.

Error creating partition key using MergeTree engine, Clickhouse

I've been trying to create model using infi.clickhouse_orm but there have been an issue with partition key
My model:
from infi.clickhouse_orm import Model, UInt16Field, Float32Field, StringField, MergeTree,DateField
class OHLC(Model):
__tablename__ = 'ohlc'
id = UInt16Field()
min = Float32Field()
max = Float32Field()
start_date = DateField()
interval = StringField()
engine = MergeTree(partition_key=['id'])
I get the error:
DB::Exception: Syntax error: .. SETTINGS index_granularity=8192.
Expected one of: Arrow, token, non-empty parenthesized list of
expressions
creating my db
""" SqlAlchemy ClickHouse database session maker """
db = Database('test', db_url=os.environ['TEST_CONNECTION'],
username=os.environ['CLICKHOUSE_USER'], password=os.environ['CLICKHOUSE_PASSWORD'])
db.create_database()
db.create_table(OHLC)
The MergeTree-engine required the primary key in the table declaration that passed in order_by-parameter:
..
engine = MergeTree(partition_key=['id'], order_by=['id'])
..
from infi.clickhouse_orm.engines import MergeTree
from infi.clickhouse_orm.fields import UInt16Field, Float32Field, StringField, DateField
from infi.clickhouse_orm.models import Model
from sqlalchemy import create_engine
class OHLC(Model):
__tablename__ = 'ohlc'
id = UInt16Field()
min = Float32Field()
max = Float32Field()
start_date = DateField()
interval = StringField()
engine = MergeTree(partition_key=['id'], order_by=['id'])
engine = create_engine('clickhouse://default:#localhost/test_001')
with engine.connect() as conn:
conn.connection.create_database()
conn.connection.create_table(OHLC)
requirements.txt
sqlalchemy==1.3.18
sqlalchemy-clickhouse==0.1.5.post0
infi.clickhouse_orm==1.3.0
Using id as partition key looks pretty suspicious, consider defining it as toYYYYMM(start_date) or something like this:
class OHLC(Model):
__tablename__ = 'ohlc'
id = UInt16Field()
min = Float32Field()
max = Float32Field()
start_date = DateField()
interval = StringField()
engine = MergeTree(partition_key=['toYYYYMM(start_date)'], order_by=['id'])

how can I make an insert of a select field with sqlalchemy?

I have a form where I have a text field and a selection field and the question I have is how can I insert the bd in the selection field, this field in the table is an external key and what I need is to insert the value of the selection field.
I would greatly appreciate your help.
#detalle_grupo_estadisticas.route("/show/<id>", methods = ['GET', 'POST'])
def show(id):
title = 'Grupo estadisticas'
page = 1
per_page = 3
CamposGrupo = forms.Fields_Detalle_Grupo_Estadisticas(request.form)
grup_list = GrupoEstadisticas.query.all()
if request.method == 'POST' and CamposGrupo.validate():
grupo_edit = DetalleGrupoEstadisticas.query.filter_by(id_detalle_grupo_estadisticas=id).first()
grupo_edit.nombre = CamposGrupo.Nombre.Data
grupo_edit.id_grupoEstadisticas = CamposGrupo.GrupoEstadistica.Value
db.session.add(grupo_edit)
db.session.commit()
return redirect(url_for('detalle_grupo_estadisticas.index'))
grupo = DetalleGrupoEstadisticas.query.filter_by(id_detalle_grupo_estadisticas=id).first()
CamposGrupo.Nombre.data = grupo.nombre
CamposGrupo.GrupoEstadistica.choices=[(g.id_grupoEstadisticas,g.nombre) for g in grup_list]
return render_template('/detalle_grupo_estadisticas/show.html', title=title, CamposGrupo = CamposGrupo, grupo = grupo)
What I want to insert is the value of the field selection field
these are the models
class DetalleGrupoEstadisticas(db.Model):
__tablename__ = 'detalle_grupo_estadisticas'
id_detalle_grupo_estadisticas = db.Column(db.Integer, primary_key=True)
nombre = db.Column(db.String(80), nullable=False)
id_grupoEstadisticas = db.Column(db.Integer, db.ForeignKey('grupo_estadisticas.id_grupoEstadisticas'))
grupoestadistica = db.relationship('GrupoEstadisticas', back_populates='detallesgrupo', lazy=True)
class GrupoEstadisticas(db.Model):
__tablename__ = 'grupo_estadisticas'
id_grupoEstadisticas = db.Column(db.Integer, primary_key=True)
nombre = db.Column(db.String(80), nullable=False)
descripcion = db.Column(db.String(200), nullable=False)
estadisticas= db.relationship('Estadisticas', back_populates='grupoestadisticas', lazy=True)
detallesgrupo= db.relationship('DetalleGrupoEstadisticas', back_populates='grupoestadistica', lazy=True)
This is how I was able to solve the problem.
view
#detalle_grupo_estadisticas.route("/show/<id>", methods = ['GET', 'POST'])
def show(id):
title = 'Grupo estadisticas'
page = 1
per_page = 3
CamposGrupo = forms.Fields_Detalle_Grupo_Estadisticas(request.form)
grup_list = GrupoEstadisticas.query.all()
if request.method == 'POST' and CamposGrupo.validate():
grupo_edit = DetalleGrupoEstadisticas.query.filter_by(id_detalle_grupo_estadisticas=id).first()
grupo_edit.nombre = CamposGrupo.Nombre.data
grupo_edit.grupoestadistica = CamposGrupo.GrupoEstadistica.data
#this is where I had the error that I was inserting in id_grupoStadisticas and it had to be with the variable of the relationship
db.session.add(grupo_edit)
db.session.commit()
return redirect(url_for('detalle_grupo_estadisticas.index'))
grupo = DetalleGrupoEstadisticas.query.filter_by(id_detalle_grupo_estadisticas=id).first()
CamposGrupo.Nombre.data = grupo.nombre
CamposGrupo.GrupoEstadistica.choices=[(g.id_grupoEstadisticas,g.nombre) for g in grup_list]
return render_template('/detalle_grupo_estadisticas/show.html', title=title, CamposGrupo = CamposGrupo, grupo = grupo)
form
class Fields_Detalle_Grupo_Estadisticas(Form):
Nombre = StringField('Grupo', validators=[InputRequired(), Length(min=2, max=30, message = 'Mayor a 2 caracteres y menor a 30')])
GrupoEstadistica = QuerySelectField('Grupo Estadistica',query_factory=lambda: GrupoEstadisticas.query,
get_pk=lambda g: g.id_grupoEstadisticas,
get_label=lambda g: g.nombre)

How to get a field from from last row of an change log table in SQLAlchemy

I have the follow example. When calling Order.next I would expect to return a single order in the with the status NEW. However I am getting Orders in other OrderStatus.
If it matters this is using SQLite backend.
class OrderStatus(enum.Enum):
NEW = 0
MAKING = 1
MADE = 2
COLLECTED = 3
class Order(Base):
__tablename__ = 'orders'
id = Column(Integer, primary_key=True)
updates = relationship("OrderUpdate", order_by = "OrderUpdate.position", collection_class=ordering_list('position'))
#hybrid_method
def next(self):
order = Order.query \
.filter(Order.status in [OrderStatus.NEW]) \
.order_by(Order.id) \
.first()
return order
#hybrid_property
def status(self):
update = OrderUpdate \
.query.filter_by(order_id = self.id) \
.order_by(OrderUpdate.id.desc()) \
.first()
if update is None:
return None
return update.status
class OrderUpdate(Base):
__tablename__ = 'order_updates'
id = Column(Integer, primary_key=True)
position = Column(Integer)
status = Column('status', Enum(OrderStatus))
comment = Column(String)
order_id = Column(Integer, ForeignKey("orders.id"))
order = relationship("Order", back_populates="updates")
I didn't check, but I think the problem with line:
.filter(Order.status in [OrderStatus.NEW])
If you need to use in condition you need to use sqlalchemy in_(). So in your case it should be like this: Order.status.in_([1, 2]). Also you can do it without in_():
Order.query.filter_by(Order.status=0).order_by(Order.id).first()
Note! About Enum. This is not about Flask or Flask-SqlAlchemy. Just for you information.
# Python 3.6.1
class OrderStatus(enum.Enum):
NEW = 0
0 in [OrderStatus.NEW] # False
0 in [OrderStatus.NEW.value] # True
val = OrderStatus(0)
val in [OrderStatus.NEW] # True
Hope this helps.

Resources