I am using Sanic framework with Gino if that matters.
The following works, it generates SQL with check constraint clause:
class Foo(db.Model):
tst2 = db.Column(db.Integer)
__table_args__ = (
sqlalchemy.CheckConstraint('tst2 > 1', name= 'foo'),
)
However, the following does not generate SQL with a check constraint clause. (It does generate all the other necessary SQL successfully):
class Bar(db.Model):
id = db.Column(db.Integer, primary_key=True)
tst2 = db.Column(db.Integer, sqlalchemy.CheckConstraint('tst2 > 1', name='bar2'))
Does Gino have a way to define CheckConstraint in column definitions?
Related
I'm trying to construct a query like this:
SELECT "Inventory".item_id, "Inventory".region
FROM "Inventory" ('PLACEHOLDER' = ('$$P_Param$$', '0'))
WHERE "Inventory".region = :region_1
My select statement is adding the HANA placeholders at the end though:
select_stmt = select(
inventory.item_id,
inventory.region
).suffix_with(placeholders).where(inventory.region== 'USA')
SELECT "Inventory".item_id, "Inventory".region
FROM "Inventory"
WHERE "Inventory".region = :region_1 ('PLACEHOLDER' = ('$$P_Param$$', '0'))
How do I suffix the from clause with the placeholders and add the where clause afterwards?
class Inventory(Base):
__tablename__ = 'Inventory'
__table_args__ = {'schema': '_SYS_BIC'}
date = Column(DateTime, primary_key=True)
item_id = Column(Integer, primary_key=True)
region = Column(String)
placeholder = "('PLACEHOLDER' = ('$$P_Param$$', '0'))"
The SAP Hana dialect does not seem to support placeholders.
As you saw suffix_with does exactly what it says, it appends a suffix to the full query.
Without dialect support, you could try using a from_statement with text which will allow to load what you need using your own SQL statements.
Let's say I have the following database schema:
class A(Base):
__tablename__ = "a_table"
id = Column(Integer, primary_key=True, autoincrement=True)
version = Column(Integer, primary_key=True, default=1)
# More columns...
bs = relationship(
"B", secondary="a2b_table", back_populates="as"
)
class B(Base):
__tablename__ = "b_table"
id = Column(Integer, primary_key=True)
as = relationship(
A, secondary="a2b_table", back_populates="bs"
)
class A2B(Base):
__tablename__ = "a2b_table"
a_id = Column(
Integer(),
primary_key=True,
)
a_version = Column(
Integer,
primary_key=True,
)
b_id = sa.Column(
Integer,
ForeignKey("b.id", name="b_fk"),
primary_key=True,
)
__table_args__ = (
ForeignKeyConstraint(
[a_id, a_version],
[A.id, A.version],
name="a_fk",
),
{},
)
Each A is identified by an id and can have multiple versions. If something changes in the columns of A (the ones not shown), I produce a new A with the same id and version+1. The relationship bs gives me all instances of B that are associated with a specific version of an A.
The problem is, that the relationship as gives me all versions of each A that is associated with a specific B. Instead, I want the relationship to contain only the latest (highest) version of each A. Following the docs, I tried to solve this with a custom primaryjoin and a window function:
partition = select(
A,
row_number()
.over(order_by=A.version.desc(), partition_by=A.id)
.label("index"),
).alias()
partitioned_as = aliased(A, partition)
B.latest_as = relationship(
partitioned_as,
primaryjoin=and_(
partition.c.index == 1,
and_(
partitioned_as.id == A2B.a_id,
partitioned_as.version == A2B.a_version,
),
),
secondary="a2b_table",
viewonly=True,
)
Unfortunately, it doesn't work and I get the warning:
SELECT statement has a cartesian product between FROM element(s) "anon_1", "a2b_table" and FROM element "a_table". Apply join condition(s) between each element to resolve.
I checked the SQL statement sqlalchemy generates and it has anon_1, i.e. the query of partition, and a_table in its FROM clause. As far as I understand it, a_table shouldn't be in the FROM clause of this statement because it is already in the FROM clause of partition. I don't know how to get rid of it.
Could anyone point me in the right direction? Thanks in advance.
I have two models:
class Profile(Base):
__tablename__ = 'profiles'
id = Column(Integer, primary_key=True)
...
stagesP_list = relationship(
'StageP',
back_populates='profiles_list',
secondary=stageP_profile
)
class Project(Base):
__tablename__ = 'projects'
id = Column(Integer, primary_key=True)
...
stagesP_list = relationship(
'StageP',
back_populates='projects_list',
secondary=stageP_project
)
I need to select Profiles for which at least one value of the Profile.stagesP_list is contained in the project.stagesP_list.
Please help to compose the query or indicate the direction in which to search.
If you have project instance loaded, you can compose the following query:
project = ...
stageP_ids = [obj.id for obj in project.stagesP_list]
query = session.query(Profile).filter(
Profile.stagesP_list.any(StageP.id.in_(stageP_ids))
)
You can also perform joins on the database directly from having only project_id:
query = (
session.query(Profile)
.join(StageP, Profile.stagesP_list)
.join(Project, StageP.projects_list)
.where(Project.id == project_id)
.distinct()
)
I want to add comments to the table and columns created of a model.
I tried the doc parameter of the Column class, like the following:
class Notice(db.Model):
__tablename__ = "tb_notice"
__table_args__ = {'mysql_engine': 'MyISAM'}
seqno = db.Column(db.Integer, primary_key=True, autoincrement=True, doc="seqno")
title = db.Column(db.String(200), nullable=False, doc="notice title")
detail = db.Column(db.TEXT, nullable=True, doc="notice detail ")
But it didn't work, the comments weren't added to the SQL creation statement, and I wonder how to add a comment to the table.
comment only supported in version 1.2
New in version 1.2:
http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.Column.params.comment
According to the documentation of doc parameter:
doc¶ – optional String that can be used by the ORM or similar to document attributes on the Python side. This attribute does not render SQL comments; use the Column.comment parameter for this purpose.
And the comment parameter:
comment¶ – Optional string that will render an SQL comment on table creation.
Please note that the comment is added in version 1.2 of SQlAlchemy
And for adding a comment for the table, you just pass additional comment attribute (according to the Table class documentation) to your __table_args__ dictionary. Which is also added in version 1.2
The code would be something like this:
class Notice(db.Model):
__tablename__ = "tb_notice"
__table_args__ = {
'mysql_engine': 'MyISAM',
'comment': 'Notice table'
}
seqno = db.Column(db.Integer, primary_key=True, autoincrement=True, doc="seqno",
comment='Integer representing the sequence number')
title = db.Column(db.String(200), nullable=False, doc="notice title",
comment='Title of the notice, represented as a string')
detail = db.Column(db.TEXT, nullable=True, doc="notice detail",
comment='Notice detail description')
The doc attribute acts as a docstring of your class:
print(Notice.title.__doc__)
will outputs:
notice title
Now the corresponding SQL table creation statement would be:
CREATE TABLE `tb_notice` (
`seqno` int(11) NOT NULL COMMENT 'Integer representing the sequence number',
`title` varchar(200) NOT NULL COMMENT 'Title of the notice, represented as a string',
`detail` text COMMENT 'Notice detail description'
) ENGINE=MyISAM DEFAULT CHARSET=utf32 COMMENT='Notice table';
You can see that comments were added correctly to both the table and the columns.
in new 1.2 version you can do
class Notice(db.Model):
__tablename__ = "tb_notice"
__table_args__ = {
'mysql_engine': 'MyISAM'
'comment': 'yeah comment'
}
Right now I'm doing this:
class MyTest(Base):
__tablename__ = 'mytest'
id = Column(Integer, primary_key = True)
name = Column(String(255), nullable=False)
created_at = Column(DateTime)
Base.metadata.create_all(engine)
But in the tutorial, another way is this:
user = Table('user', metadata,
Column('user_id', Integer, primary_key = True),
Column('user_name', String(16), nullable = False),
Column('email_address', String(60)),
Column('password', String(20), nullable = False)
)
Which method should I be using? By the way, I will be using sqlalchemy-migrate, (I don't know if that will change the answer)
If you want to just access the data from the table and want to use SQLAlchemy as a mediator then you have to use TABLE. But if you want to use the each row of the table as an separate object then you have to use declarative base.
Which way you have to use is up to you and how you want to use SQLAlchemy.