Index a relationship in SQLAlchemy and Almbic - python-3.x

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)

Related

How to rename keys in response from database by pydantic schema - FastAPI

I have a model from my database in models.py:
class Something(Base):
__tablename__ = "something"
DATE = Column(Date, primary_key=True, index=True )
a = Column(String, primary_key=True, index=True)
b = Column(Integer, primary_key=True, index=True)
c = Column(Float, index=True)
d = Column(Integer, index=True)
e = Column(Integer, index=True)
f = Column(Float, index=True)
g = Column(Float, index=True)
h = Column(Integer, index=True)
and a pydantic model in schema.py:
class Something(BaseModel):
DATE: date
a: str
b: int
c: float = None
d: int = None
e: int = None
f: float = None
g: float = None
h: int = None
class Config:
orm_mode = True
I get data from the database which go through the ORM and in app.get() I declare the response model equal to List[schema.Something], but I want to change the names from the database a, b, c, d to more beautiful names.
Is there a solution like mapping names in NestJS?
Try to use aliases, this is what option allow_population_by_field_name allows to do, for example:
class Person(BaseModel):
first_name: str = Field(..., alias='first')
last_name: str = Field(..., alias='second')
class Config:
allow_population_by_field_name = True
p = Person(**{'first': 'John', 'second': 'White'})
print(p.__dict__)
# {'first_name': 'John', 'last_name': 'White'}

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.

SQLAlchemy Order joined table by field in another joined table

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)

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