sqlalchemy how to access Joined Model attribute without foreign key? - python

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'])

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.

sqlalchemt---SAWarning: fully NULL primary key identity cannot load any object

model:
'''任务工单'''
__tablename__ = 'task'
id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=True)
user_id = db.Column(db.Integer, index=True, nullable=False)
dep_id = db.Column(db.Integer, index=True, nullable=False)
title = db.Column(db.String(200), nullable=False, index=True)
content = db.Column(db.Text, nullable=False)
cate = db.Column(db.SmallInteger, default=1,`enter code here`)
add_time = db.Column(db.Integer, default=int(time.time()), comment="添加时间")
is_top = db.Column(db.SmallInteger, default=0, comment="是否加急 1--加急 0--不加急")
desgin_id = db.Column(db.Integer,comment="设计人员的id")
update_time = db.Column(db.Integer, comment="修改时间")
review_time = db.Column(db.Integer, comment="审核时间")
assignment_time = db.Column(db.Integer, comment='分配时间')
fiannce_time = db.Column(db.Integer, comment='完成时间')
invalid_time = db.Column(db.Integer, comment='无效时间')
desgin_time = db.Column(db.Integer, comment="开始设计时间")
state = db.Column(db.SmallInteger, default=1, comment="状态:1--初始化待分配 2--带设计 3--设计中 4--提交待审核(审核中) 5--驳回 7--完成 0--无效")
use:
taskDicts = Task.query.filter_by(state=state).order_by(desc(Task.is_top),asc(Task.add_time)).offset(offset).limit(10).all()
venv/lib/python3.7/site-packages/sqlalchemy/orm/loading.py:246:
SAWarning: fully NULL primary key identity cannot load any object.
This condition may raise an error in a future release.

How to set relationship between two tables in SQLAlchemy?

I have got two tables:
Announcements
AnnouncementsSchedule
Relationship is one(Announcements) to many(AnnouncementsSchedule) by keys:
Announcements.id = AnnouncementsSchedule.announcements_id
I tried to describe models in SQLAlchemy:
The first table is described as model:
class Announcements(db.Model):
__tablename__ = 'announcements'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(150), nullable=False)
text = db.Column(db.Text(), nullable=False)
category = db.Column(db.Integer(), nullable=False)
subcategory = db.Column(db.Integer(), nullable=False)
offer_type = db.Column(db.Integer(), nullable=False)
url = db.Column(db.String(150), nullable=True)
status = db.Column(db.Integer(), nullable=False)
#children = relationship("AnnouncementsSchedule", back_populates="announcements")
Second is:
class AnnouncementsSchedule(db.Model):
__tablename__ = 'announcements_schedule'
id = Column(Integer, primary_key=True)
week_day = db.Column(db.Integer(), nullable=True)
week_all = db.Column(db.Integer(), nullable=False)
time = db.Column(db.Time(), nullable=False)
announcement_id = Column(Integer, ForeignKey('announcements.announcements_id'))
What I do wrong?
You have a mistake in the column name (announcements doesn't have announcement_id ):
# announcement_id = Column(Integer, ForeignKey('announcements.announcements_id'))
# change to ->
announcement_id = Column(Integer, ForeignKey('announcements.id'))

how to insert symbol(,) to result in SQLAlchemy level?

#mapping class
class Billing(Base):
__tablename__ = 'billing'
id = Column(Integer, primary_key=True)
billingdate= Column(DateTime, nullable=False)
amt = Column(Integer, nullable=False)
rate = Column(Integer, nullable=False)
fk_cpid = Column(Integer, ForeignKey('company.cpid'))
#run
query = self.mssql_session.query(Billing.billingdate).all()
result
$83749283 => $83,749,283
how to insert symbol(,) at Billing.billingdate in ONLY SQLAlchemy level?
Replace, SubString?
from sqlalchemy.ext.hybrid import hybrid_property
class Billing(Base):
__tablename__ = 'billing'
id = Column(Integer, primary_key=True)
billingdate= Column(DateTime, nullable=False)
_amt = Column(Integer, nullable=False)
rate = Column(Integer, nullable=False)
fk_cpid = Column(Integer, ForeignKey('company.cpid'))
#hybrid_property
def amt(self):
return '${:,}'.format(self._amt)
Hopes, this code can help you.

How to fetch pairs from join where second value can be none, left join

I have two models in database like
class Base(object):
def __tablename__(self):
return self.__name__.lower()
id = Column(Integer, primary_key=True, nullable=False)
utc_time = Column(BigInteger, default=utc_time, onupdate=utc_time)
class EntityModel(Base):
__tablename__ = 'entities'
town_id = Column(Integer, ForeignKey('towns.id', ondelete='CASCADE'), nullable=False)
type = Column(Integer, nullable=False)
level = Column(Integer, nullable=False, default=Level.LEVEL_ONE)
energy = Column(Float, nullable=False, default=0)
x = Column(Integer, nullable=False)
y = Column(Integer, nullable=False)
class CommandModel(Base):
__tablename__ = 'commands'
entity_id = Column(Integer, ForeignKey('entities.id', ondelete='CASCADE'), nullable=False)
command = Column(Integer, nullable=False)
started_at = Column(BigInteger, nullable=False)
ends_at = Column(BigInteger, nullable=False)
type = Column(Integer, default=None)
Entity can have one or none command. How to fetch pairs entity, command (entity can exists without command)
I tried like but it doesn't work
for e, c in session.query(EntityModel, CommandModel).join(CommandModel).filter(EntityModel.town_id == 100).all():
You can use outerjoin for a left outer join, which seems to be what you want.
http://docs.sqlalchemy.org/en/rel_0_7/orm/query.html#sqlalchemy.orm.query.Query.outerjoin

Categories