Database tables generation using sqlalchemy - python

I'm currently trying to generate SQL tables using the sqlalchemy library.
I have two tables : t_volume and t_volume_snapshot
class Volume(...):
""" Represent a volume element"""
__tablename__ = "t_volume"
created_at = Column(DateTime, nullable=False)
deleted_at = Column(DateTime, nullable=False)
volume_id = Column(String(length=255), nullable=False, primary_key=True)
volume_name = Column(String(length=255), nullable=False)
volume_type = Column(String(length=255), nullable=False)
volume_disk_space = Column(Integer, nullable=False)
class VolumeSnapshot(...):
""" Represent a volume snapshot element"""
__tablename__ = "t_volume_snapshot"
created_at = Column(DateTime, nullable=False)
deleted_at = Column(DateTime, nullable=False)
volume_snapshot_id = Column(String(length=255), nullable=False, primary_key=True)
volume_snapshot_name = Column(String(length=255), nullable=False)
volume_id = Column(String(length=255), ForeignKey("t_volume.volume_id"))
I would like that a volume snapshot refers to a volume using the value volume_id. I tried to define the t_volume_snapshot.volume_id column as a ForeignKey pointing to t_volume.volume_id but all I get is
OperationalError: (OperationalError) (1005, "Can't create table 'db.t_volume_snapshot' (errno: 150)")
I'm not used to sqlalchemy and SQL in general so I'm probably missing something...

You should be able to do something like below
class Volume(...):
""" Represent a volume element"""
__tablename__ = "t_volume"
created_at = Column(DateTime, nullable=False)
deleted_at = Column(DateTime, nullable=False)
volume_id = Column(String(length=255), nullable=False, primary_key=True)
volume_name = Column(String(length=255), nullable=False)
volume_type = Column(String(length=255), nullable=False)
volume_disk_space = Column(Integer, nullable=False)
snapshots = relationship("VolumeSnapshot", back_populates="t_volume")
class VolumeSnapshot(...):
""" Represent a volume snapshot element"""
__tablename__ = "t_volume_snapshot"
created_at = Column(DateTime, nullable=False)
deleted_at = Column(DateTime, nullable=False)
volume_snapshot_id = Column(String(length=255), nullable=False, primary_key=True)
volume_snapshot_name = Column(String(length=255), nullable=False)
snapshot_volume_id = Column(String(length=255), ForeignKey("volume_id"))
This should establish a bidirectional connection.

Related

sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Order->order, expression 'Status' failed to locate a name ('Status')

Cannot save record to my db.
I created endpoint which makes user and saves him to db:
#router.post("/user/register/", tags=['user'], status_code=201)
async def user_register_web(user: RegisterWebSchema, db: Session = Depends(get_db)):
if user.password != user.password_repeat:
raise HTTPException(status_code=404, detail="Passwords dont match each other!")
db_user = UserModel(name=user.name.title(), surname=user.surname.title(), email=user.email,
phone_number=user.phone_number, login=user.login, password=user.password,
photo=None, is_admin=False, coins=0)
db.add(db_user)
db.commit()
db.refresh(db_user)
return {"JWT Token": signJWT(user.email),
**user.dict()}
Here is model of my User:
class User(Base):
__tablename__ = "user"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, index=True)
name = Column(String(50), nullable=False)
surname = Column(String(50), nullable=False)
email = Column(String(50), unique=True, nullable=False)
phone_number = Column(String(15), unique=True, nullable=False)
login = Column(String(50), unique=True, nullable=False)
password = Column(String(80), nullable=False)
photo = Column(String(80), nullable=True)
is_admin = Column(Boolean, nullable=False)
coins = Column(Integer, nullable=False)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
address_id = Column(Integer, ForeignKey("address.id"), nullable=False)
address = relationship("Address", back_populates="user")
pin = relationship("Pin", back_populates="user")
payment_card = relationship("PaymentCard", back_populates="user")
order = relationship("Order", back_populates="user")
feedback = relationship("Feedback", back_populates="user")
post = relationship("Post", back_populates="user")
comment = relationship("Comment", back_populates="user")
animal = relationship("Animal", back_populates="user")
walk = relationship("Walk", back_populates="user")
and here is the error I get:
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Order->order, expression 'Status' failed to locate a name ('Status'). If this is a class name, consider adding this relationship() to the <class 'database.models.OrderModel.Order'> class after both dependent classes have been defined.
model of Order:
class Order(Base):
__tablename__ = "order"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, index=True)
order_code = Column(String(15), nullable=True)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
status_id = Column(Integer, ForeignKey("status.id"), nullable=False)
status = relationship("Status", back_populates="order")
payment_method_id = Column(Integer, ForeignKey("payment_method.id"), nullable=False)
payment_method = relationship("PaymentMethod", back_populates="order")
user_id = Column(Integer, ForeignKey("user.id"), nullable=False)
user = relationship("User", back_populates="order")
post_office = relationship("PostOffice", back_populates="order")
product = relationship("Product", secondary=OrderProduct, back_populates="order")
and model of Status:
class Status(Base):
__tablename__ = "status"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), nullable=False)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
order = relationship("Order", back_populates="status")
I createrd migration successfully and then db. I dont understand why it shows lack of relationship, which i created. And it appears in lines of codes which dont even use these Tables.
In order to make it work I had to import all of my modules into api file with endpoint. I don't know why but it works right now.

sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class

I am beginner trying to make a relational database in Flask project using SQLalchemy
This is the error that I am getting when I try to register a user:-
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Question->question, expression 'Answer' failed to locate a name ('Answer'). If this is a class name, consider adding this relationship() to the <class 'nothingness.models.Question'> class after both dependent classes have been defined.
DB relationships are:-
User (Many to Many) Table
User (1 to Many) Question
Question (1 to Many) Answer
Table (1 to Many) Question
Here are my codes
from datetime import datetime
from nothingness import db
members = db.Table(
"member",
db.Column("id", db.Integer, primary_key=True),
db.Column("table_id", db.Integer, db.ForeignKey("table.id")),
db.Column("user_id", db.Integer, db.ForeignKey("user.id")),
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(25), unique=True, nullable=False)
name = db.Column(db.String(25), nullable=False)
email = db.Column(db.String(), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default="default.jpg")
password = db.Column(db.String(60), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
member = db.relationship("Table", secondary=members, backref=db.backref("members", lazy=True))
prashna = db.relationship("Question", backref="user", lazy=True)
def __repr__(self):
return f"User('{self.name}', '{self.username}', '{self.email}', '{self.image_file}')db.Model"
class Table(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(25), nullable=False)
key = db.Column(db.String(5), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
question = db.relationship("Question", backref="questions", lazy=True)
def __repr__(self):
return f"Table('{self.id}', '{self.name}', '{self.key}', {self.created_at})"
class Question(db.Model):
id = db.Column(db.Integer, primary_key=True)
question = db.Column(db.String(255), nullable=False)
asked_by = db.Column(db.Integer, db.ForeignKey("user.id"))
asked_to = db.Column(db.Integer, nullable=False)
answer = db.relationship("Answer", backref="question", lazy=True)
table = db.Column(db.Integer, db.ForeignKey("table.id"))
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
class Answer:
id = db.Column(db.Integer, primary_key=True)
points = db.Column(db.Integer)
answer = db.Column(db.String(255), nullable=False)
answered_by = db.Column(db.Integer, nullable=False)
table_id = db.Column(db.Integer, nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
question = db.Column(db.Integer, db.ForeignKey("question.id"))
def __repr__(self):
return f"Answer('{self.points}', '{self.answer}', '{self.created_at}')"
This error occurred because I forgot to subclass Answer with db.Model

How to fetch rows from postgresql database by specifying schema?

I am new to Postgresql & Sqlalchemy. I have below file layout.py. In this, I have created two table name "layout" & "layout default" under "col" schemas.
import json, decimal
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy import create_engine
from sqlalchemy import Column, String, Integer, TIMESTAMP, Sequence, text, types
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import datetime, uuid
db_string = "postgres://postgres:PWDd#10.**.**.***:1111/d_demo"
Base = declarative_base()
db = create_engine(db_string)
class Layout(Base):
__tablename__ = "col.layout"
layout_id = Column(UUID(as_uuid=True), nullable=False, primary_key=True)
name = Column(String(1000), nullable=False)
layout = Column(String(10000), nullable=False)
grid_id = Column(Integer, nullable=False)
user_id = Column(Integer, nullable=False)
issystemlayout = Column(Integer, default=0, nullable=False)
ispublic = Column(Integer, default=0, nullable=False)
isactive = Column(Integer, default=0, nullable=False)
createdby = Column(Integer, default=1, nullable=False)
createdat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedby = Column(Integer, default=1, nullable=False)
Insert datas :
INSERT INTO col.layout(layout_id,name,layout,grid_id,user_id,ispublic,issystemlayout,isactive,createdby,createdat, modifiedat,modifiedby) VALUES('ba0233d7-d917-4303-b4bf-c2544a617d33','Layout1','{"Name":"Manish","Place":"Pune"}',1,12345,'1','0','1','201819','2015/05/20','2015/05/16',123);
Fetching data :
Session = sessionmaker(bind=db)
session = Session()
Base.metadata.create_all(db)
session.query("SET search_path TO col;")
result = []
selected_columns = Layout.__table__.columns
print("Selected columns {}".format(selected_columns))
record = session.query(Layout).with_entities(*selected_columns).all()
for row in record:
print(row)
result.append(row)
print(json.dumps(result))
session.close()
But it is not showing data under "col" schemas. Please suggest, how should I do?
https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/table_config.html#table-configuration
Schema for postgres database can be passed through table_args attribute either as a tuple or a dict.
So for your problem your class definition should have this extra attribute:
class Layout(Base):
__tablename__ = "layout"
__table_args__ = {"schema": "col"}
layout_id = Column(UUID(as_uuid=True), nullable=False, primary_key=True)
name = Column(String(1000), nullable=False)
layout = Column(String(10000), nullable=False)
grid_id = Column(Integer, nullable=False)
user_id = Column(Integer, nullable=False)
issystemlayout = Column(Integer, default=0, nullable=False)
ispublic = Column(Integer, default=0, nullable=False)
isactive = Column(Integer, default=0, nullable=False)
createdby = Column(Integer, default=1, nullable=False)
createdat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedby = Column(Integer, default=1, nullable=False)

sqlalchemy how to access Joined Model attribute without foreign key?

I want to join three Model and access all attribute in them , but I don't have authority to add a foreign key.
This can be solve by use raw sql, but I want to use sqlalchemy Model.
Models are generated from existing database:
class Marketingplanproduct(Base):
__tablename__ = 'marketingplanproducts'
id = Column(String(36, 'utf8_bin'), primary_key=True, server_default=text("''"))
price = Column(Integer, nullable=False)
marketing_plan_id = Column(ForeignKey('marketingplans.id'), index=True)
product_id = Column(ForeignKey('products.id'), index=True)
is_deleted = Column(Integer, nullable=False)
marketing_plan = relationship('Marketingplan')
product = relationship('Product')
class Marketingplan(Base):
__tablename__ = 'marketingplans'
id = Column(String(36, 'utf8_bin'), primary_key=True, server_default=text("''"))
subject = Column(String(50), nullable=False, index=True)
description = Column(String(1000), index=True)
time_start_plan = Column(BigInteger, nullable=False, index=True)
time_end_plan = Column(BigInteger, nullable=False, index=True)
product_count = Column(Integer, nullable=False)
user_id_create = Column(String(36, 'utf8_bin'), nullable=False, server_default=text("''"))
review_status = Column(Integer, nullable=False)
user_id_review = Column(String(36, 'utf8_bin'), nullable=False, server_default=text("''"))
time_review = Column(BigInteger, nullable=False)
is_deleted = Column(Integer, nullable=False)
time_create = Column(BigInteger, nullable=False, index=True)
time_update = Column(BigInteger, nullable=False, index=True)
user_id_update = Column(String(36, 'utf8_bin'), nullable=False, server_default=text("''"))
accepted_count = Column(Integer, nullable=False)
total_execute_log_count = Column(Integer, nullable=False)
price_change_category = Column(Integer, nullable=False)
store_implement = Column(Integer, nullable=False)
class Marketingplanstoremap(Base):
__tablename__ = 'marketingplanstoremaps'
id = Column(String(36, 'utf8_bin'), primary_key=True, server_default=text("''"))
marketing_plan_id = Column(String(36, 'utf8_bin'), nullable=False, index=True, server_default=text("''"))
store_id = Column(String(36, 'utf8_bin'), nullable=False, index=True, server_default=text("''"))
My code:
def get_marketingplans(self, store_id=None, product_id=None, start_date=None, end_date=None):
query = self.Session().query(Marketingplanproduct)\
.join(Marketingplan, Marketingplanproduct.marketing_plan_id==Marketingplan.id)\
.join(Marketingplanstoremap, Marketingplan.id==Marketingplanstoremap.marketing_plan_id)\
.filter(Marketingplan.is_deleted==0)\
.filter(Marketingplanproduct.is_deleted==0)
if store_id:
query.filter(Marketingplanstoremap.store_id==store_id)
if product_id:
query.filter(Marketingplanproduct.store_id==product_id)
if start_date:
s = ensure_millisecond(start_date)
query.filter(Marketingplan.time_start_plan>=s)
if end_date:
e = ensure_millisecond(end_date)
query.filter(Marketingplan.time_start_plan<e)
marketingplans = query.all()
df = pd.DataFrame([ (mp.store_id, mp.marketing_plan.product_id, mp.price) for mp in marketingplans], columns=['store_id', 'product_id', 'price'])
return df
My code failed because there is no mp.store_id .
It seems you have not configured such an ORM relationship path that you could access a Marketingplanstoremap through Marketingplanproduct. Since you are already including both in the query using joins, you could simply add Marketingplanstoremap as a second entity in the query:
query = self.Session().query(Marketingplanproduct, Marketingplanstoremap)\
...
...
results = query.all()
df = pd.DataFrame([(mpsm.store_id, mpp.product_id, mpp.price)
for mpp, mpsm in results],
columns=['store_id', 'product_id', 'price'])
Or you could just ask for the attributes you need directly:
query = self.Session().query(Marketingplanstoremap.store_id,
Marketingplanproduct.product_id,
Marketingplanproduct.price)\
select_from(Marketingplanproduct)\
...
results = query.all()
df = pd.DataFrame(results, columns=['store_id', 'product_id', 'price'])

Why am I getting InstrumentedAttribute instead of basequery

I have created two models in flask using flask_sqlalchemy as follows:
class Analytics(db.Model, IdMixin, ModelMixin):
__tablename__ = "analytics"
record_id = Column(Integer, ForeignKey("record.id"), nullable=True)
created_at = Column(TIMESTAMP, nullable=True)
updated_at = Column(TIMESTAMP, nullable=True)
class HitLog(db.Model, IdMixin, TimestampMixin, ModelMixin):
__tablename__ = "hit_logs"
record_id = Column(Integer, ForeignKey("record.id"), nullable=True)
url = Column(Text, nullable=False, default='')
ip = Column(String(100), nullable=False, default='0.0.0.0', index=True)
referer = Column(Text, nullable=False, default='')
source = Column(String(255), nullable=False, default='', index=True)
query = Column(Text, nullable=False, default='')
user_agent = Column(String(255), nullable=False, default='')
created_at = Column(TIMESTAMP, nullable=True, index=True)
updated_at = Column(TIMESTAMP, nullable=True, index=True)
deleted_at = Column(TIMESTAMP, nullable=True, index=True)
Both the models are created the same way but still when I check for type, I get different results:
print type(Analytics.query)
print type(HitLog.query)
Gives me:
<class 'flask_sqlalchemy.BaseQuery'>
<class 'sqlalchemy.orm.attributes.InstrumentedAttribute'>
Why is it so?
You have a column named query in HitLog.

Categories