Modifying existing value in SQLAlchemy object - python

I'm trying to take an existing string in a retrieved SQLAlchemy object and concatenate it with a second string, however no value is being written.
print(messages)
testsuite = session.query(Testsuite).get(test_id)
testsuite.console += messages
session.commit()
Inspecting the database, the record has kept its original empty value - messages was never added.
My Testsuite model is as follows:
# Represents schema - used by engine to create tables etc.
Base = declarative_base()
# These SQL fields are horrendously inefficient - need replacing ASAP!
class Testsuite(Base):
"""Testsuite model to map testsuite in progress to SQL DB."""
__tablename__ = 'testsuites'
id = Column(Integer, primary_key=True)
name = Column(String)
timestamp = Column(DateTime, default=datetime.datetime.utcnow)
product_name = Column(String)
serial_number = Column(String)
total_tests = Column(Integer)
completed_tests = Column(Integer)
console = Column(Text)
report_id = Column(Integer)
testcases = relationship('Testcase', backref='testsuite')
result = Column(String)
def __init__(self, testsuite_name, product_name, serial_number, total_tests=0):
self.name = testsuite_name
self.product_name = product_name
self.serial_number = serial_number
self.total_tests = total_tests
self.completed_tests = 0
self.result = 'pending'
I've read that the way I am modifying my objects can lead to race conditions, though I am unsure of a suitable alternative. Can anyone point out the issues with what I'm doing and why my messages string isn't being added?
Thanks :)

So after a bit of experimentation, it seems that the code was failing because Testsuite.console never had an initial value.
The code now works with the following change to the mode:
class Testsuite(Base):
"""Testsuite model to map testsuite in progress to SQL DB."""
__tablename__ = 'testsuites'
id = Column(Integer, primary_key=True)
name = Column(String)
timestamp = Column(DateTime, default=datetime.datetime.utcnow)
product_name = Column(String)
serial_number = Column(String)
total_tests = Column(Integer)
completed_tests = Column(Integer, default=0)
console = Column(String, default="Waiting for incoming log data...\n")
report_id = Column(Integer)
testcases = relationship('Testcase', backref='testsuite')
result = Column(String, default='pending')
def __init__(self, testsuite_name, product_name, serial_number, total_tests=0):
self.name = testsuite_name
self.product_name = product_name
self.serial_number = serial_number
self.total_tests = total_tests

Related

How to create two tables at the same time in FAST API

i want to create two tables at the same time. and also use one tables primary key to another tables foreign key at the same time.
def createOrderPlace(request: OrderCreatePlaceOrder, db: Session):
#try:
x = format(random.randint(10000,99999), '04d')
exists_x=db.query(OrderModel).filter(OrderModel.order_id == x).first()
if exists_x:
x = format(random.randint(10000,99999), '04d')
order_create = OrderModel(
user_id=request.currentUser.user_id,
name=request.currentUser.name,
email=request.currentUser.email,
orderAmount=request.subtotal,
cvv_id=request.currentUser.cvv_id,
card_name=request.currentUser.card_name,
card_number=request.currentUser.card_number,
card_month=request.currentUser.card_month,
card_year=request.currentUser.card_year,
order_id=x,
billing_first_name=request.currentUser.billing_first_name,
billing_last_name=request.currentUser.billing_last_name,
billing_phone_number=request.currentUser.billing_phone_number,
billing_country=request.currentUser.billing_country,
billing_division=request.currentUser.billing_division,
billing_district=request.currentUser.billing_district,
billing_address=request.currentUser.billing_address,
billing_police_station=request.currentUser.billing_police_station,
billing_post_code=request.currentUser.billing_post_code,
shipping_first_name=request.currentUser.shipping_first_name,
shipping_last_name=request.currentUser.shipping_last_name,
shipping_phone_number=request.currentUser.shipping_phone_number,
shipping_country=request.currentUser.shipping_country,
shipping_division=request.currentUser.shipping_division,
shipping_district=request.currentUser.shipping_district,
shipping_address=request.currentUser.shipping_address,
shipping_police_station=request.currentUser.shipping_police_station,
shipping_post_code=request.currentUser.shipping_post_code,
)
db.add(order_create)
db_orderid = (
db.query(OrderModel)
.filter(OrderModel.user_id == request.currentUser.user_id)
.first()
)
for dic in request.cartItems:
order_item_a = OrderItemsModel(
item_id=dic.item_id,
name=dic.item_name,
price=dic.item_price,
description=dic.item_description,
user_id=dic.user_id,
payment_order_id=dic.payment_order_id,
)
db.add(order_item_a)
db.commit()
return {'invoice':request,'detail': f'Successfully Buy this Service, Check it on My service','message':True,'order_number':order_create.order_id}
i tried this but thats not work. I am using two models
class OrderModel(Base): **(model 1)**
__tablename__ = "tbl_order_and_payment-order"
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
email = Column(String)
orderAmount = Column(Integer)
transactionId = Column(String)
isDelivered = Column(Boolean)
user_id = Column(Integer, ForeignKey('tbl_stu_usr-users.id'))
purchase_date = Column(DateTime, default=datetime.utcnow)
#updated_at = Column(DateTime, default=datetime.utcnow)
cvv_id=Column(String)
card_name=Column(String)
card_number=Column(String)
card_month=Column(Integer)
card_year=Column(Integer)
order_id = Column(Integer)
billing_first_name=Column(String)
billing_last_name=Column(String)
billing_phone_number=Column(String)
billing_country=Column(String)
billing_division=Column(String)
billing_district=Column(String)
billing_address=Column(String)
billing_police_station=Column(String)
billing_post_code=Column(Integer)
i have another model
class OrderItemsModel(Base):
__tablename__ = "tbl_order_and_payment-order_items"
id = Column(Integer, primary_key=True, index=True)
item_id=Column(Integer, ForeignKey('tbl_stu_adm-pricing_plan-service.id'))
user_id = Column(Integer, ForeignKey('tbl_stu_usr-users.id'))
name = Column(String)
price = Column(Integer)
description=Column(String)
product_type=Column(String)
payment_order_id=Column(Integer, ForeignKey('tbl_order_and_payment-order.id'))
i am using "tbl_order_and_payment-order.id" this primary tho this "tbl_order_and_payment-order_items" tables as payment_order_id=Column(Integer, ForeignKey('tbl_order_and_payment-order.id'))
i just want to create two tables at the same time.

SQLAlchemy - How to correctly connect two sets of data?

I am hoping for some guidance about what I believe is going to be a common pattern in SQLAlchemy for Python. However, I have so far failed to find a simple explanation for someone new to SQLAlchemy.
I have the follow objects:
Customers
Orders
Products
I am building a Python FastAPI application and I want to be able to create customers, and products individually. And subsequently, I want to then be able to create an order for a customer that can contain 1 or more products. A customer will be able to have multiple orders also.
Here are my SQLAlchemy models:
order_products = Table('order_products', Base.metadata,
Column('order_id', ForeignKey('orders.id'), primary_key=True),
Column('product_id', ForeignKey('products.id'), primary_key=True)
)
class Customer(Base):
__tablename__ = "customers"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
address = Column(String)
phonenumber = Column(String)
email = Column(String, unique=True, index=True)
is_active = Column(Boolean, default=True)
orders = relationship("Order", back_populates="customers")
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True, index=True)
ordernumber = Column(String, index=True)
customer_id = Column(Integer, ForeignKey("customers.id"))
customers = relationship("Customer", back_populates="orders")
products = relationship("Product", secondary="order_products", back_populates="orders")
class Product(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
size = Column(Integer)
order_id = Column(Integer, ForeignKey("orders.id"))
orders = relationship("Order", secondary="order_products", back_populates="products")
And here are my CRUD operations:
def create_customer(db: Session, customer: customer.CustomerCreate):
db_customer = models.Customer(name = customer.name, address = customer.address, email=customer.email, phonenumber=customer.phonenumber)
db.add(db_customer)
db.commit()
db.refresh(db_customer)
return db_customer
def create_product(db: Session, product: product.Productreate):
db_product = models.Product(name = product.name, size = product.size)
db.add(db_product)
db.commit()
db.refresh(db_product)
return db_product
def create_order(db: Session, order: order.OrderCreate, cust_id: int):
db_order = models.Order(**order.dict(), customer_id=cust_id)
db.add(db_order)
db.commit()
db.refresh(db_order)
return db_order
def update_order_with_product(db: Session, order: order.Order):
db_order = db.query(models.Order).filter(models.Order.id==1).first()
if db_order is None:
return None
db_product = db.query(models.Order).filter(models.Product.id==1).first()
if db_order is None:
return None
db_order.products.append(db_product)
db.add(db_order)
db.commit()
db.refresh(db_order)
return db_order
All of the CRUD operations work apart from update_order_with_product which gives me this error:
child_impl = child_state.manager[key].impl
KeyError: 'orders'
I'm not sure if I am taking the correct approach to the pattern needed to define the relationships between my models. If not, can someone point me in the right direction of some good examples for a beginner?
If my pattern is valid then there must be an issue with my CRUD operation trying to create the relationships? Can anyone help with that?
This query could be a problem:
db_product = db.query(models.Order).filter(models.Product.id==1).first()
Should probably be:
db_product = db.query(models.Product).filter(models.Product.id==1).first()
because you want to get a Product instance, not Order.
When you update a record you should not add it to the session (because it has been registered to the session when you queried the record).
def update_order_with_product(db: Session, order: order.Order):
db_order = db.query(models.Order).filter(models.Order.id==1).first()
if db_order is None:
return None
db_product = db.query(models.Product).filter(models.Product.id==1).first()
if db_product is None:
return None
db_order.products.append(db_product)
db.commit()
db.refresh(db_order)
return db_order

fastAPI sqlalchemy - inner JOIN on 2 tables

I have a restapi up and running using the fastAPI framework, which is starting to work well.
Now: I already have my MySQL code on how to inner join on 2 tables, and I want to be able to do the same, just using sqlalchemy.
Firstly, here is my SQL code which works perfectly:
select `the_user`.`email_adress`, `the_exercise`.`exercise_name`, `run_the_workout`.`repetitions`,`run_the_workout`.`sets`,`run_the_workout`.`pause_time`,`run_the_workout`.`day_to_perform_the_task`
from `workout_plan_task` `run_the_workout`
inner join `user_profiles` `the_user` on `run_the_workout`.the_user=`the_user`.user_id
inner join `exercises` `the_exercise` on `the_exercise`.`exercise_ID` = `run_the_workout`.`the_exercise`
WHERE `run_the_workout`.the_user=1
Now, here are my table models in SQL alchemy, representing the "user_profiles", "exercises" and the "workout_plan_task" table:
#models.py:
class UserProfiles(Base):
__tablename__ = "user_profiles"
user_ID = Column(Integer, primary_key=True, index=True)
email_adress = Column(String, unique=True)
age = Column(Integer)
sex = Column(Integer)
height = Column(Integer)
weight = Column(Integer)
main_goal = Column(Integer)
level_experience = Column(Integer)
profile_created_at = Column(Date)
class Exercises(Base):
__tablename__ = "exercises"
exercise_ID = Column(Integer, primary_key=True, index=True)
exercise_name = Column(String)
exercise_type = Column(String, nullable=True)
muscle_groups_worked_out = Column(String)
equipment_ID = Column(Integer, nullable=True)
class WorkOutPlanTask(Base):
__tablename__ = "workout_plan_task"
task_ID = Column(Integer, primary_key=True, index=True)
user_ID = Column(Integer, ForeignKey("user_profiles.user_ID"))
workout_plan_ID = Column(Integer, ForeignKey("workout_plan.workout_plan_ID"))
exercise_ID = Column(Integer, ForeignKey("exercises.exercise_ID"))
repetitions = Column(Integer)
sets = Column(Integer)
pause_time = Column(Integer)
day_to_perform_the_task = Column(String)
inside my "crud.py" file, im trying to run the query using inner joins:
#crud.py
def get_workout_plan_for_user(db: Session, user_id:int):
return db.query(models.WorkOutPlanTask).join(models.UserProfiles, models.UserProfiles.user_ID == models.WorkOutPlanTask.user_ID).join(models.Exercises, models.Exercises.exercise_ID == models.WorkOutPlanTask.exercise_ID).filter(models.UserProfiles.user_ID == user_id)
and inside my #main.py i have this:
#app.get("/all_workout_plan_tasks_for_user/{user_id}")
def get_workout_plan_for_user_by_userID(user_id: int, db:Session = Depends(get_db)):
db_workout_plan = crud.get_workout_plan_for_user(db, user_id=user_id)
if db_workout_plan is None:
raise HTTPException(status_code=404, detail="sorry.. no workoutplans found ..")
return [schemas.a_workout_plan_task.from_orm(v) for v in db.query(...)]
This gives me the error:
sqlalchemy.exc.InvalidRequestError: SQL expression, column, or mapped entity expected - got 'Ellipsis'
Anyone here who could help me?
That's a funny mistake, take a look at the return statement:
return [schemas.a_workout_plan_task.from_orm(v) for v in db.query(...)]
You're passing Ellipsis to your db.query, and obviously, it's not the expected value.

SQLAlchemy inserting data into two tables

I am just working on my first App based on SQLAlchemy and after couple hours of work with the documentation and some videos, I still can't fix the issue.
My app is a simple CRUD grocery list. I want to keep the category of the product in separate table so here comes relationship module of the SQLAlchemy. Error msg gives me no hint at all tbh.
engine = create_engine(my_database, echo = True)
connection = engine.connect()
Base = declarative_base()
session = sessionmaker(bind=engine)
class MyEnum(enum.Enum):
one = "pieces"
two = "kg"
class ProductTable(Base):
__tablename__ = 'product'
product_id = Column(Integer, primary_key=True)
product_name = Column(String(30), nullable=False)
product_quantity = Column(Integer, nullable=False)
product_type = Column(Enum(MyEnum), nullable=False)
category_id = Column(Integer, ForeignKey('category.id'), nullable=False)
category = relationship("category", back_populates="product")
product_description = Column(String(255))
class CategoryTable(Base):
__tablename__ = 'category'
id = Column(Integer, primary_key=True)
category_name = Column(String(25), nullable=False)
Base.metadata.create_all(engine)
session = session()
cc_product = ProductTable(product_id=1,
product_name="cucumber",
product_quantity="1",
product_type="kg",
product_description="For the salad")
cc_category= CategoryTable(category_name="vegetables")
session.add(cc_product, cc_category)
session.commit()
I. Creation of the tables finished smoothly with no errors, however, is the creation itself designed properly? Each product has single category but one category should be assigned to one or more product. I made that based on one to one relationship.
II. Inserting data to both tables. I want to insert data like:
Product_id = 1
Product_name = Cucumber
Product_quantity = 1
Product_type = "kg" or "pieces"
Category = Vegetables ( from the category table)
Description = "blah blah blah"
I think there is something wrong not only with the data inserting process but also with the tables creation.
Here is the error, which tbh, doesn't tell me anything:
sqlalchemy.exc.ArgumentError: relationship 'category' expects a class or a mapper argument (received: <class 'sqlalchemy.sql.schema.Table'>)
You have two mistakes:
you wrote "category" as the Mapper class instead of "CategoryTable"
forgot to create products on 'CategoryTable'
class ProductTable(Base):
__tablename__ = 'product'
product_id = Column(Integer, primary_key=True)
product_name = Column(String(30), nullable=False)
product_quantity = Column(Integer, nullable=False)
product_type = Column(Enum(MyEnum), nullable=False)
category_id = Column(Integer, ForeignKey('category.id'), nullable=False)
categories = relationship("CategoryTable", back_populates="products")
product_description = Column(String(255))
class CategoryTable(Base):
__tablename__ = 'category'
id = Column(Integer, primary_key=True)
category_name = Column(String(25), nullable=False)
products = relationship('ProductTable', back_populates='categories')
Some more changes are still needed:
change CategoryTable to Category (also for ProductTable, better names)
you'll have constraints failing after you'll get things running...

How to obtain data from a table that has been joined

I have two tables items and games.
#app.route('/collection/<username>/<int:page>/<platform>/<path:path>')
def collection(username, page=1, platform='DMG', path=None):
# first I get the user by his username
user = User.query.filter_by(username=username).first()
# then I get all items form the user and related games
items = user.items.join(Game)
# until now it works perfectly fine
# now I would like to obtain all titles from the joined table games
game_titles = items.filter(Game.title).all()
# but unfortunately I get only an empty list
What is missing?
Here my models:
class Game(db.Model):
__tablename__ = 'games'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(64), index=True)
publisher = db.Column(db.String(32), index=True)
region = db.Column(db.String(3), index=True)
code_platform = db.Column(db.String(3), index=True)
code_identifier = db.Column(db.String(4), index=True)
code_region = db.Column(db.String(3), index=True)
code_revision = db.Column(db.String(1))
code = db.Column(db.String(16), index=True, unique=True)
year = db.Column(db.Integer)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
items = db.relationship('Item', backref='game', lazy='dynamic')
def __repr__(self):
return '<Game %r>' % (self.title)
class Item(db.Model):
__tablename__ = 'items'
id = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(8), index=True)
cart = db.Column(db.Boolean)
box = db.Column(db.Boolean)
manual = db.Column(db.Boolean)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
def __repr__(self):
return '<Collection %r>' % (self.user_id)
You have two options. Using SQLAlchemy ORM:
game_titles = [i.game.title for i in user.items]
To make this more efficient, you can apply the joinedload optimization:
game_titles = [i.game.title for i in user.items.options(joinedload(Item.game))]
Alternatively, you can use SQLAlchemy core if all you care about are the titles (and nothing else):
game_titles = user.items.join(Item.game).with_entities(Game.title).all()
You can even skip fetching the user altogether if you don't care about the user at all:
game_titles = User.query.join(User.items).join(Item.game).filter(User.username == username).with_entities(Game.title).all()
As an aside, .filter and .filter_by correspond to the selection operator in relational algebra, whereas .with_entities and db.session.query(...) correspond to the projection operator, contrary to what you had initially assumed.
Try something like this:
items.join(Game).options(joinedload(Item.game, innerjoin=True))
Essentially, you're joining with Game and explicitly loading it, where the innerjoin forces it to do so only on the games listed in the table you're joining with (items)

Categories

Resources