How to properly handle many to many in async sqlalchemy? - python

I was trying to implement many to many relationship between tables.
When I use backpopulates all tags for a specific user must be in the tags field.
The tables are successfully created.
Users and tags are added.
Link table too.
import asyncio
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.util import await_only, greenlet_spawn
from sqlalchemy import Column, Table, ForeignKey
from sqlalchemy.orm import declarative_base, relationship
from sqlalchemy.dialects.postgresql import VARCHAR, INTEGER
Base = declarative_base()
user_tag = Table('user_tag', Base.metadata,
Column('user_id', INTEGER, ForeignKey('users.id')),
Column('tag_id', INTEGER, ForeignKey('tags.id'))
)
class User(Base):
__tablename__ = 'users'
id = Column(INTEGER, primary_key=True)
name = Column(VARCHAR(32), nullable=False, unique=True)
tags = relationship("Tag",
secondary=user_tag,
back_populates="users")
class Tag(Base):
__tablename__ = 'tags'
id = Column(INTEGER, primary_key=True)
tag = Column(VARCHAR(255), nullable=False, unique=True)
users = relationship("User",
secondary=user_tag,
back_populates="tags")
async def main():
engine = create_async_engine(
"postgresql+asyncpg://postgres:pgs12345#localhost/test",
echo=False,
)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await conn.run_sync(Base.metadata.create_all)
users = [User(name="p1"), User(name="p2"), User(name="p3")]
tags = [Tag(tag="tag1"), Tag(tag="tag2"), Tag(tag="tag3")]
async with AsyncSession(engine) as session:
async with session.begin():
session.add_all(users)
session.add_all(tags)
for user in users:
await session.refresh(user)
for tag in tags:
await session.refresh(tag)
for user in users:
for i in range(3, user.id - 1, -1):
await session.execute(user_tag.insert().values(user_id=user.id, tag_id=i))
await session.commit()
for user in users:
await session.refresh(user)
for tag in tags:
await session.refresh(tag)
tags = await greenlet_spawn(users[0].tags)
print(tags)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
When I run the program, it crashes with:
File "C:\Sources\asyncSQLAl test\main.py", line 48, in <module>
loop.run_until_complete(main())
File "C:\Users\Stanislav\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line
642, in run_until_complete
return future.result()
File "C:\Sources\asyncSQLAl test\main.py", line 41, in main
tags = await greenlet_spawn(await users[0].tags)
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\orm\attributes.py", line 480, in __get__
return self.impl.get(state, dict_)
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\orm\attributes.py", line 931, in get
value = self.callable_(state, passive)
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\orm\strategies.py", line 879, in _load_for_state
return self._emit_lazyload(
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\orm\strategies.py", line 1036,
in _emit_lazyload
result = session.execute(
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\orm\session.py", line 1689, in
execute
result = conn._execute_20(statement, params or {}, execution_options)
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1582, in
_execute_20
return meth(self, args_10style, kwargs_10style, execution_options)
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\sql\lambdas.py", line 481, in _execute_on_connection
return connection._execute_clauseelement(
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1451, in
_execute_clauseelement
ret = self._execute_context(
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1813, in
_execute_context
self._handle_dbapi_exception(
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1998, in
_handle_dbapi_exception
util.raise_(exc_info[1], with_traceback=exc_info[2])
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\util\compat.py", line 207, in raise_
raise exception
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\engine\base.py", line 1770, in
_execute_context
self.dialect.do_execute(
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\engine\default.py", line 717, in do_execute
cursor.execute(statement, parameters)
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\dialects\postgresql\asyncpg.py", line 449, in execute
self._adapt_connection.await_(
File "C:\Sources\asyncSQLAl test\venv\lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 60, in await_only
raise exc.MissingGreenlet(
sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_() here. Was IO attempted in an unexpected place? (Background on this error at: http://sqlalche.me/e/14/xd2s)
sys:1: RuntimeWarning: coroutine 'AsyncAdapt_asyncpg_cursor._prepare_and_execute' was never awaited
I don't quite understand how greenlet_spawn works here and where it should be used in this example.
For example, same program, but in sync style
from sqlalchemy import Column, Table, ForeignKey
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.dialects.postgresql import VARCHAR, INTEGER
Base = declarative_base()
user_tag = Table('user_tag', Base.metadata,
Column('user_id', INTEGER, ForeignKey('users.id')),
Column('tag_id', INTEGER, ForeignKey('tags.id'))
)
class User(Base):
__tablename__ = 'users'
id = Column(INTEGER, primary_key=True)
name = Column(VARCHAR(32), nullable=False, unique=True)
tags = relationship("Tag",
secondary=user_tag,
back_populates="users")
class Tag(Base):
__tablename__ = 'tags'
id = Column(INTEGER, primary_key=True)
tag = Column(VARCHAR(255), nullable=False, unique=True)
users = relationship("User",
secondary=user_tag,
back_populates="tags")
def __str__(self):
return self.tag
def main():
engine = create_engine(
"postgresql+psycopg2://postgres:pgs12345#localhost/test",
echo=False,
)
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
users = [User(name="p1"), User(name="p2"), User(name="p3")]
tags = [Tag(tag="tag1"), Tag(tag="tag2"), Tag(tag="tag3")]
with session.begin():
session.add_all(users)
session.add_all(tags)
for user in users:
for i in range(3, user.id - 1, -1):
session.execute(user_tag.insert().values(
user_id=user.id, tag_id=i))
session.commit()
for tag in users[0].tags:
print(tag, end=" ")
main()
Gives me:
tag1 tag2 tag3

I've been stuck on this today too and I've narrowed it down to the fact that a lazyload is attempted, which GreenLet is not happy about. I wasn't sure whether this was just my lack of skill but I've found this article that details some of the common errors:
https://matt.sh/sqlalchemy-the-async-ening, where it's mentioned that this very issue will occur in this way. Furthermore, the docs go into detail about needing to avoid lazyloading: https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html.
My solution at the moment is to effectively prefetch the Child relation upon the initial query of the Parent object and then manipulate it from there. Whether this is a true bug, in the sense that it should work in async when it already works in sync or simply a limitation of the async method, I've no idea.
Edit 06/08/21, here is how I am prefetching relationships:
import sqlalchemy as sa
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from . import models
async def get_parent_prefetch_children(db: AsyncSession, parent_id: int) -> models.Parent:
result = await db.execute(
sa.select(models.Parent).where(models.Parent.id == parent_id).options(
selectinload(models.Parent.children)
)
)
return result.scalar()
In your case, you call users[0].tags, which makes a lazyload and fails. In order for you to avoid this, you must refetch users with their tags eagerly loaded.

From their official doc for relationship, you can use lazy="joined" to ask the SQLAlchemy do prefetch for you on session.refresh(...) or session.execute(select(...)). This will do joined style eagerly load at the time you query for the object. Note that this may introduce performance issue to your application since sometime you are not going to access the foreign'd objects while the database will still do joined style query for you.
tags = relationship("Tag",
secondary=user_tag,
back_populates="users",
lazy="joined")
The results and SQL stmt looks like:
>>>tags = users[0].tags
>>>print(tags)
[<__main__.Tag object at 0x10bc68610>, <__main__.Tag object at 0x10bc41d00>, <__main__.Tag object at 0x10bc12b80>]
>>>from sqlalchemy.future import select
>>>print(select(User))
FROM users LEFT OUTER JOIN (user_tag AS user_tag_1 JOIN tags AS tags_1 ON tags_1.id = user_tag_1.tag_id) ON users.id = user_tag_1.user_id

Related

sqlalchemy.orm.exc.UnmappedInstanceError: Class 'db.models.Inventory.InventoryModel' is not mapped

I am in the process of building several example APIs to and ran into this 'is not mapped' sqlalchemy.orm.exe.UnmappedInstance Error issue. I believe this error would possible be generated if I was trying to pass an object instance that wasn't a model, however, I am passing a pydanic model within the db.add() method which is mapped (or at least I think it is.) So, I'm not sure why I'm getting this error when the object being passed to db.Add (new_inventory) is a prudence model that is aligned to the base schema. What am I missing? Or educate me on why I'm getting a Unmapped Instance Error when I can clearly see that the type received is a mapped pedantic model. I've raved existing Stack Overflow post which was centered around using marshmallows, which I prefer to make that an 'if all else fails' solution. Any solution to get the code I have in place massaged would be highly appreciated.
Using Python 3.10.4 / Pydantic / SqlAlchemy / FastAPI
file name c:\app\main.py
'''python
from msilib import schema
mport psycopg2
from psycopg2.extras import RealDictCursor
from os import stat
from fastapi import Depends, FastAPI, Response, status, HTTPException
from pydantic import BaseModel
from typing import Optional
import pdb
from db.conn import Postgre
from db.sql_alchemy import db_engine, fetch_db, Base
from db.models.Inventory import InventorySchema, InventoryModel
from sqlalchemy.orm import Session
from pydantic import BaseModel
Base.metadata.create_all(bind=db_engine)
app = FastAPI()
#app.get("/fetch/vehicles", status_code=status.HTTP_200_OK)
def fetch_vehiles(db: Session = Depends(fetch_db)):
vehicles = db.query(InventorySchema).all()
print(vehicles)
return {"all vehicles": vehicles}
#app.post("/post/vehicles",status_code=status.HTTP_201_CREATED)
def insert_vechiles(inventory: InventoryModel, db: Session = Depends(fetch_db)):
new_inventory = InventoryModel(
name = inventory.name,
price = inventory.price,
color = inventory.color,
manufactured_by = inventory.manufactured_by,
model = inventory.model,
size = inventory.size,
quantity = inventory.quantity,
active = inventory.active)
pdb.set_trace()
db.add(new_inventory) # <---generates error
# db.commit()
# db.refresh(new_intentory)
return {"Posted": new_inventory}
# file name: c:\db\models\Inventory.py
from email.policy import default
from msilib import schema
from xmlrpc.client import Boolean, boolean
from psycopg2 import Timestamp
from pydantic import BaseModel
from db.sql_alchemy import Base
from sqlalchemy import TIMESTAMP, Column, Integer, String, Boolean
from sqlalchemy.sql.expression import text
from sqlalchemy.sql.sqltypes import TIMESTAMP
class InventoryModel(BaseModel):
name: str = 'Yshmael'
price: str = '3.00'
color: str = 'blue'
manufactured_by: str = 'ford'
model: str = 'branch'
size: str = '4 door'
quantity: str = '10'
active: str = 'False'
class InventorySchema(Base):
__tablename__ = "vehicles"
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String, nullable=False)
price = Column(String, nullable=False)
color = Column(String, nullable=False)
manufactured_by = Column(String, nullable=False)
model = Column(String, nullable=False)
size = Column(String, nullable=False)
quantity = Column(String, nullable=False)
active = Column(String, nullable=False)
created_on = Column(TIMESTAMP(timezone=True), nullable=False,
server_default=text('now()'))
'''
StackTrace
Traceback (most recent call last):
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 366, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 75, in __call__
return await self.app(scope, receive, send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\fastapi\applications.py", line 269, in __call__
await super().__call__(scope, receive, send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\applications.py", line 124, in __call__
await self.middleware_stack(scope, receive, send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
raise exc
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\middleware\errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\exceptions.py", line 93, in __call__
raise exc
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\exceptions.py", line 82, in __call__
await self.app(scope, receive, sender)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 21, in __call__
raise e
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
await self.app(scope, receive, send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\routing.py", line 670, in __call__
await route.handle(scope, receive, send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\routing.py", line 266, in handle
await self.app(scope, receive, send)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\routing.py", line 65, in app
response = await func(request)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\fastapi\routing.py", line 227, in app
raw_response = await run_endpoint_function(
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\fastapi\routing.py", line 162, in run_endpoint_function
return await run_in_threadpool(dependant.call, **values)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\starlette\concurrency.py", line 41, in run_in_threadpool
return await anyio.to_thread.run_sync(func, *args)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\anyio\to_thread.py", line 31, in run_sync
return await get_asynclib().run_sync_in_worker_thread(
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 937, in run_sync_in_worker_thread
return await future
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 867, in run
result = context.run(func, *args)
File "C:\QA\Dev\projects\testdriven.io\posting_system\.\app\main.py", line 40, in insert_vechiles
db.add(new_inventory)
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\sqlalchemy\orm\session.py", line 2605, in add
util.raise_(
File "C:\QA\Dev\projects\testdriven.io\posting_system\venv\lib\site-packages\sqlalchemy\util\compat.py", line 207, in raise_
raise exception
**sqlalchemy.orm.exc.UnmappedInstanceError: Class 'db.models.Inventory.InventoryModel' is not mapped**
It seems that you are confused with the inheritance of model and schema, BaseModel is for schemas and Base is for models.
Try to change the classes of:
class InventoryModel(BaseModel):
class InventorySchema(Base):
__tablename__ = "vehicles"
to:
class InventoryModel(Base):
__tablename__ = "vehicles"
class InventorySchema(BaseModel):

db.drop_all() gives no such table error when I try to clear my database using command line arguments [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am using a command line argument of -clear to empty the database of my application before the program starts up. My problem is that calling db.drop_all() from the run.py file throws a "no such table" error. I am wondering what the best approach to clearing my database before running the application would be. Here is my relevant code.
run.py
# Imports
from wms import desktopApp, db
from wms.functions import load_data
import argparse
# Parsing command line arguments
description = """IMPORTANT: When loading information to the database, please insure that all files are stored in the
resources folder and that the file format matches that described in the application documentation."""
parser = argparse.ArgumentParser(description=description)
# Arguments
parser.add_argument("-warehouses",
help="Loads the supplied warehouses.csv file into the database when the program is run.",
action="store_true")
parser.add_argument("-itemTemplates",
help="Loads the supplied item_templates.csv file into the database when the program is run.",
action="store_true")
parser.add_argument("-items",
help="Loads the supplied items.csv file into the database when the program is run.",
action="store_true")
parser.add_argument("-clear",
help="Clears the existing database.",
action="store_true")
args = parser.parse_args()
successful = load_data(args.warehouses, args.itemTemplates, args.items)
if not successful:
quit()
if __name__ == '__main__':
# Clear database
if args.clear:
while True:
confirmation = input("Are you sure you want to clear the database? (y/n): ")
if confirmation.lower() in ["yes", "y"]:
# Drop db logic
db.drop_all()
print("Database cleared.")
break
elif confirmation.lower() in ["no", "n"]:
print("Good thing we double checked.")
break
else:
pass
desktopApp.run()
desktopApp.keep_server_running()
init.py
# Imports
from flask import Flask
from flaskwebgui import FlaskUI
from flask_sqlalchemy import SQLAlchemy
# App config
app = Flask(__name__)
app.config["DEBUG"] = True
app.config["TESTING"] = True
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.config["SECRET_KEY"] = '8e3416a9c67b328517b7b758875aaea0'
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # Removes warning message in console
# Database config
db = SQLAlchemy(app)
from wms.models import Warehouse, Item, ItemTemplate
db.create_all()
# Desktop UI config
desktopApp = FlaskUI(app,
width=1200,
height=675,
browser_path='C:\Program Files (x86)\Google\Chrome\Application\chrome.exe')
models.py
# Imports
from wms import db
from sqlalchemy.ext.hybrid import hybrid_property
# Constants
MAXIMUM_NAME_LEN = 14
LARGE_SCALE_SIZE = 150
# Template for creating items
class ItemTemplate(db.Model):
"""This template will simply store the information related to an item type.
Individual items that will be associated with the warehouse they're stored in
will inherit this information from the item templates."""
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(MAXIMUM_NAME_LEN), unique=True, nullable=False)
price = db.Column(db.Float, nullable=False)
cost = db.Column(db.Float, nullable=False)
size = db.Column(db.Integer, nullable=False)
low_threshold = db.Column(db.Integer, nullable=False)
instances = db.relationship('Item', backref='item_template', lazy=True) # Instances using this item template
#hybrid_property
def total_stock(self):
total_stock = 0
for instance in self.instances:
total_stock += instance.quantity
return total_stock
#hybrid_property
def possible_revenue(self):
return self.total_stock * (self.price - self.cost)
#hybrid_property
def warehouses(self):
return [instance.warehouse for instance in self.instances]
#hybrid_property
def stock(self):
stock = 0
for instance in self.instances:
stock += instance.quantity
return stock
# Actual items
class Item(db.Model):
"""This template will be used to represent the actual items that are associated with a warehouse."""
id = db.Column(db.Integer, primary_key=True)
quantity = db.Column(db.Integer, nullable=False)
warehouse = db.Column(db.String(MAXIMUM_NAME_LEN), db.ForeignKey('warehouse.name'), nullable=False)
item_template_id = db.Column(db.Integer, db.ForeignKey('item_template.id'), nullable=False)
# Warehouse
class Warehouse(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(MAXIMUM_NAME_LEN), unique=True, nullable=False)
capacity = db.Column(db.Integer, nullable=False)
items = db.relationship("Item", backref="home_warehouse", lazy=True)
#hybrid_property
def remaining_capacity(self):
capacityUsed = 0
for item in self.items:
capacityUsed += item.quantity * ItemTemplate.query.filter_by(id=item.item_template_id).first().size
return self.capacity - capacityUsed
#hybrid_property
def possible_revenue(self):
revenue = 0
for item in self.items:
item_temp = ItemTemplate.query.filter_by(id=item.item_template_id).first()
revenue += item.quantity * (item_temp.price - item_temp.cost)
return revenue
#hybrid_property
def total_production_cost(self):
total_production_cost = 0
for item in self.items:
total_production_cost += item.quantity * ItemTemplate.query.filter_by(id=item.item_template_id).first().cost
return total_production_cost
#hybrid_property
def low_stock_items(self):
low_stock = []
for item in self.items:
if item.quantity <= ItemTemplate.query.filter_by(id=item.item_template_id).first().low_threshold:
low_stock.append(item)
return low_stock
#hybrid_property
def large_scale_items(self):
large = []
for item in self.items:
if ItemTemplate.query.filter_by(id=item.item_template_id).first().size >= LARGE_SCALE_SIZE:
large.append(item)
return large
#hybrid_property
def item_names(self):
return [ItemTemplate.query.filter_by(id=item.item_template_id).first().name for item in self.items]
Error message:
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\base.py", line 1799, in _execute_context
self.dialect.do_execute(
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\default.py", line 717, in do_execute
cursor.execute(statement, parameters)
sqlite3.OperationalError: no such table: warehouse
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\waitress\channel.py", line 397, in service
task.service()
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\waitress\task.py", line 168, in service
self.execute()
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\waitress\task.py", line 434, in execute
app_iter = self.channel.server.application(environ, start_response)
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2091, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2076, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2073, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1518, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1516, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1502, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "C:\coding\python\projects\WMS\wms\routes.py", line 22, in home
warehouseList = Warehouse.query.all()
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\orm\query.py", line 2711, in all
return self._iter().all()
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\orm\query.py", line 2846, in _iter
result = self.session.execute(
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\orm\session.py", line 1689, in execute
result = conn._execute_20(statement, params or {}, execution_options)
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\base.py", line 1611, in _execute_20
return meth(self, args_10style, kwargs_10style, execution_options)
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\sql\elements.py", line 325, in _execute_on_connection
return connection._execute_clauseelement(
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\base.py", line 1478, in _execute_clauseelement
ret = self._execute_context(
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\base.py", line 1842, in _execute_context
self._handle_dbapi_exception(
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\base.py", line 2023, in _handle_dbapi_exception
util.raise_(
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\util\compat.py", line 207, in raise_
raise exception
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\base.py", line 1799, in _execute_context
self.dialect.do_execute(
File "C:\Users\golin\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlalchemy\engine\default.py", line 717, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: warehouse
[SQL: SELECT warehouse.id AS warehouse_id, warehouse.name AS warehouse_name, warehouse.capacity AS warehouse_capacity
FROM warehouse]
(Background on this error at: https://sqlalche.me/e/14/e3q8)

How to solve maximum recursion depth exceeded when autoloading one to one columns

I am tying to link two databases via a one to one relationship. One is already establlished the other db is dynamic in terms of the number of columns (except for the key column).
The following code:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data/items.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False
db = SQLAlchemy(app)
class Items(db.Model):
item_id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(40))
item_embeddings = db.relationship('ItemEmbeddings', backref='items', uselist=False,lazy='dynamic')
def __repr__(self):
return '<Item {}>'.format(self.item_id)
class ItemEmbeddings(db.Model):
item_id = db.Column('item_id', db.Integer, db.ForeignKey('items.item_id'), primary_key=True)
__table_args__ = {
'metadata':db.metadata,
'autoload_with': db.engine,
'extend_existing': True,
}
yields this error:
File ".../lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 855, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File ".../lib/python3.7/site-packages/sqlalchemy/sql/selectable.py", line 645, in foreign_keys
return self.foreign_keys
File ".../lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 855, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File ".../lib/python3.7/site-packages/sqlalchemy/sql/selectable.py", line 643, in foreign_keys
self._init_collections()
RecursionError: maximum recursion depth exceeded
Should i solve this by setting some ForeignKey constraint?
The db does not exist yet, so i run db.create_all after importing the model. is there some solution to make this work?

Pyramid: sqlalchemy.exc.OperationalError

I'm following a Pyramid tutorial: http://pyramid-blogr.readthedocs.io/en/latest/project_structure.html and using Windows 8.
Current result: When I open my localhost address (in firefox), I get the following error:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: entries [SQL: 'SELECT entries.id AS entries_id, entries.title AS entries_title, entries.body AS entries_body, entries.created AS entries_created, entries.edited AS entries_edited \nFROM entries ORDER BY entries.created DESC\n LIMIT ? OFFSET ?'] [parameters: (5, 0)]
Traceback (most recent call last):
File "C:\Python34\Lib\site-packages\pyramid_debugtoolbar\panels\performance.py", line 71, in noresource_timer_handler
result = handler(request)
File "C:\Python34\Lib\site-packages\pyramid\tweens.py", line 62, in excview_tween
reraise(*attrs['exc_info'])
File "C:\Python34\Lib\site-packages\pyramid\compat.py", line 148, in reraise
raise value
File "C:\Python34\Lib\site-packages\pyramid\tweens.py", line 22, in excview_tween
response = handler(request)
File "C:\Python34\Lib\site-packages\pyramid_tm\__init__.py", line 119, in tm_tween
reraise(*exc_info)
File "C:\Python34\Lib\site-packages\pyramid_tm\compat.py", line 15, in reraise
raise value
File "C:\Python34\Lib\site-packages\pyramid_tm\__init__.py", line 98, in tm_tween
response = handler(request)
File "C:\Python34\Lib\site-packages\pyramid\router.py", line 158, in handle_request
view_name
File "C:\Python34\Lib\site-packages\pyramid\view.py", line 547, in _call_view
response = view_callable(context, request)
File "C:\Python34\Lib\site-packages\pyramid\viewderivers.py", line 442, in rendered_view
result = view(context, request)
File "C:\Python34\Lib\site-packages\pyramid\viewderivers.py", line 147, in _requestonly_view
response = view(request)
File "c:\projects\turing_chat\turing_blog\turing_blog\views\default.py", line 9, in index_page
paginator = BlogRecordService.get_paginator(request, page)
File "c:\projects\turing_chat\turing_blog\turing_blog\services\blog_record.py", line 30, in get_paginator
url_maker=url_maker)
File "C:\Python34\Lib\site-packages\paginate_sqlalchemy\__init__.py", line 35, in __init__
super(SqlalchemyOrmPage, self).__init__(*args, wrapper_class=SqlalchemyOrmWrapper, **kwargs)
File "C:\Python34\Lib\site-packages\paginate\__init__.py", line 251, in __init__
self.items = list(self.collection[first:last])
File "C:\Python34\Lib\site-packages\paginate_sqlalchemy\__init__.py", line 20, in __getitem__
return self.obj[range]
File "C:\Python34\Lib\site-packages\sqlalchemy\orm\query.py", line 2489, in __getitem__
return list(res)
File "C:\Python34\Lib\site-packages\sqlalchemy\orm\query.py", line 2797, in __iter__
return self._execute_and_instances(context)
File "C:\Python34\Lib\site-packages\sqlalchemy\orm\query.py", line 2820, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "C:\Python34\Lib\site-packages\sqlalchemy\engine\base.py", line 945, in execute
return meth(self, multiparams, params)
File "C:\Python34\Lib\site-packages\sqlalchemy\sql\elements.py", line 263, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "C:\Python34\Lib\site-packages\sqlalchemy\engine\base.py", line 1053, in _execute_clauseelement
compiled_sql, distilled_params
File "C:\Python34\Lib\site-packages\sqlalchemy\engine\base.py", line 1189, in _execute_context
context)
File "C:\Python34\Lib\site-packages\sqlalchemy\engine\base.py", line 1393, in _handle_dbapi_exception
exc_info
File "C:\Python34\Lib\site-packages\sqlalchemy\util\compat.py", line 202, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "C:\Python34\Lib\site-packages\sqlalchemy\util\compat.py", line 185, in reraise
raise value.with_traceback(tb)
File "C:\Python34\Lib\site-packages\sqlalchemy\engine\base.py", line 1182, in _execute_context
context)
File "C:\Python34\Lib\site-packages\sqlalchemy\engine\default.py", line 469, in do_execute
cursor.execute(statement, parameters) sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: entries [SQL: 'SELECT entries.id AS entries_id, entries.title AS entries_title, entries.body AS entries_body, entries.created AS entries_created, entries.edited AS entries_edited \nFROM entries ORDER BY entries.created DESC\n LIMIT ? OFFSET ?'] [parameters: (5, 0)]
Expected Result: The tutorial states that I should be seeing a page with text that reads: "No blog entries are found" when I open my localhost address.
These are the file contents of some of the files I created / edited as part of tutorial:
blog_record.py
> import sqlalchemy as sa from paginate_sqlalchemy import
> SqlalchemyOrmPage #<- provides pagination from ..models.blog_record
> import BlogRecord
>
>
> class BlogRecordService(object):
>
> #classmethod
> def all(cls, request):
> query = request.dbsession.query(BlogRecord)
> return query.order_by(sa.desc(BlogRecord.created)) # ^^ will return a query object that can return an entire dataset(in desc order)
> when needed.
> #classmethod
> def by_id(cls, _id, request):
> query = request.dbsession.query(BlogRecord)
> return query.get(_id) # ^^ return a single entry by id or the None object if nothing is found
> #classmethod
> def get_paginator(cls, request, page=1):
> query = request.dbsession.query(BlogRecord)
> query = query.order_by(sa.desc(BlogRecord.created))
> query_params = request.GET.mixed()
>
> def url_maker(link_page):
> # replace page param with values generated by paginator
> query_params['page'] = link_page
> return request.current_route_url(_query=query_params)
>
> return SqlalchemyOrmPage(query, page, items_per_page=5,
> url_maker=url_maker)
default.py
from pyramid.view import view_config
from ..services.blog_record import BlogRecordService
#view_config(route_name='home',
renderer='pyramid_blogr:templates/index.jinja2')
def index_page(request):
page = int(request.params.get('page', 1))
paginator = BlogRecordService.get_paginator(request, page)
return {'paginator': paginator}
# ^^ We first retrieve from the URL's request object the page number that we want to present to the user.
# If the page number is not present, it defaults to 1.
# The paginator object returned by BlogRecord.get_paginator will then be used in the template
# to build a nice list of entries.
# Everything we return from our views in dictionaries will be available in templates as variables.
# So if we return {'foo':1, 'bar':2}, then we will be able to access the variables
# inside the template directly as foo and bar.
#view_config(route_name='auth', match_param='action=in', renderer='string',
request_method='POST')
#view_config(route_name='auth', match_param='action=out', renderer='string')
def sign_in_out(request):
return {}
user.py
import datetime #<- will be used to set default dates on models
from turing_blog.models.meta import Base #<- we need to import our sqlalchemy metadata from which model classes will inherit
from sqlalchemy import (
Column,
Integer,
Unicode, #<- will provide Unicode field
UnicodeText, #<- will provide Unicode text field
DateTime, #<- time abstraction field
)
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Unicode(255), unique=True, nullable=False)
password = Column(Unicode(255), nullable=False)
last_logged = Column(DateTime, default=datetime.datetime.utcnow)
models/__init__.py
from sqlalchemy import engine_from_config
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import configure_mappers
import zope.sqlalchemy
# import or define all models here to ensure they are attached to the
# Base.metadata prior to any initialization routines
from .user import User
from .blog_record import BlogRecord
# run configure_mappers after defining all of the models to ensure
# all relationships can be setup
configure_mappers()
def get_engine(settings, prefix='sqlalchemy.'):
return engine_from_config(settings, prefix)
def get_session_factory(engine):
factory = sessionmaker()
factory.configure(bind=engine)
return factory
def get_tm_session(session_factory, transaction_manager):
"""
Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
This function will hook the session to the transaction manager which
will take care of committing any changes.
- When using pyramid_tm it will automatically be committed or aborted
depending on whether an exception is raised.
- When using scripts you should wrap the session in a manager yourself.
For example::
import transaction
engine = get_engine(settings)
session_factory = get_session_factory(engine)
with transaction.manager:
dbsession = get_tm_session(session_factory, transaction.manager)
"""
dbsession = session_factory()
zope.sqlalchemy.register(
dbsession, transaction_manager=transaction_manager)
return dbsession
def includeme(config):
"""
Initialize the model for a Pyramid app.
Activate this setup using ``config.include('turing_blog.models')``.
"""
settings = config.get_settings()
# use pyramid_tm to hook the transaction lifecycle to the request
config.include('pyramid_tm')
session_factory = get_session_factory(get_engine(settings))
config.registry['dbsession_factory'] = session_factory
# make request.dbsession available for use in Pyramid
config.add_request_method(
# r.tm is the transaction manager used by pyramid_tm
lambda r: get_tm_session(session_factory, r.tm),
'dbsession',
reify=True
)
models/blog_record.py
import datetime #<- will be used to set default dates on models
from turing_blog.models.meta import Base #<- we need to import our sqlalchemy metadata from which model classes will inherit
from sqlalchemy import (
Column,
Integer,
Unicode, #<- will provide Unicode field
UnicodeText, #<- will provide Unicode text field
DateTime, #<- time abstraction field
)
from webhelpers2.text import urlify #<- will generate slugs e.g. converts "foo Bar Baz" to "foo-Bar-Baz"
from webhelpers2.date import distance_of_time_in_words #<- human friendly dates
class BlogRecord(Base):
__tablename__ = 'entries'
id = Column(Integer, primary_key=True)
title = Column(Unicode(255), unique=True, nullable=False)
body = Column(UnicodeText, default=u'')
created = Column(DateTime, default=datetime.datetime.utcnow)
edited = Column(DateTime, default=datetime.datetime.utcnow)
#property
def slug(self):
return urlify(self.title)
#property
def created_in_words(self):
return distance_of_time_in_words(self.created,
datetime.datetime.utcnow())
I suspect there is a simple mistake I have made that is causing this error e.g. not installing Pyramid properly. It would be great if someone could assist me. I can provide more details as well.
You need to run initialize_pyramid_blogr_db script that creates database tables.
You should have virtualenv folder somewhere and there is either bin or Scripts folder where Python packages install their command line scripts. Locate initialize_pyramid_blogr_db and full file system path to it.
1) Make sure you have your virtual environment activated (activate.bat)
2) Then run within your project folder::
python \path\bin\initialize_pyramid_blogr_db developmnt.ini

SQLAlchemy Attempting to Twice Delete Many to Many Secondary Relationship

I have a product model with a many to many relationship to product_categories as described below:
class Product(Base):
""" The SQLAlchemy declarative model class for a Product object. """
__tablename__ = 'products'
id = Column(Integer, primary_key=True)
part_number = Column(String(10), nullable=False, unique=True)
name = Column(String(80), nullable=False, unique=True)
description = Column(String(2000), nullable=False)
categories = relationship('Category', secondary=product_categories,
backref=backref('categories', lazy='dynamic'))
class Category(Base):
""" The SQLAlchemy declarative model class for a Category object. """
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
lft = Column(Integer, nullable=False)
rgt = Column(Integer, nullable=False)
name = Column(String(80), nullable=False)
description = Column(String(2000), nullable=False)
order = Column(Integer)
products = relationship('Product', secondary=product_categories,
backref=backref('products', lazy='dynamic', order_by=name))
product_categories = Table('product_categories', Base.metadata,
Column('products_id', Integer, ForeignKey('products.id')),
Column('categories_id', Integer, ForeignKey('categories.id'))
)
Then, I'm trying to delete this object with:
product = DBSession.query(Product).filter_by(name = 'Algaecide').one()
DBSession().delete(product)
But, what I get is the error message StaleDataError: DELETE statement on table 'product_categories' expected to delete 1 row(s); Only 0 were matched.. If you notice, it appears to be running the DELETE statement twice. So, the first time it's successfully removes the product_id from the product_categories table, but then attempts to do it yet again for whatever reason, and then decides it needs to throw an exception because it's not there.
>>> Attempting to delete the product 'Algaecide' assigned to categories: [<myproject.models.category.Category object at 0x106fa9d90>]
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] SELECT categories.id AS categories_id, categories.lft AS categories_lft, categories.rgt AS categories_rgt, categories.name AS categories_name, categories.description AS categories_description, categories.`order` AS categories_order
FROM categories, product_categories
WHERE %s = product_categories.products_id AND categories.id = product_categories.categories_id ORDER BY categories.name
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] (109L,)
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] DELETE FROM product_categories WHERE product_categories.products_id = %s AND product_categories.categories_id = %s
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] (109L, 18L)
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] DELETE FROM product_categories WHERE product_categories.products_id = %s AND product_categories.categories_id = %s
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] (109L, 18L)
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] ROLLBACK
21:39:50 ERROR [pyramid_debugtoolbar][Dummy-2] Exception at http://0.0.0.0:6543/product/Algaecide/edit
traceback url: http://0.0.0.0:6543/_debug_toolbar/exception?token=6344937a98ee26992689&tb=4421411920
Traceback (most recent call last):
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_debugtoolbar-2.3-py2.7.egg/pyramid_debugtoolbar/toolbar.py", line 178, in toolbar_tween
response = _handler(request)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_debugtoolbar-2.3-py2.7.egg/pyramid_debugtoolbar/panels/performance.py", line 57, in resource_timer_handler
result = handler(request)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid/tweens.py", line 21, in excview_tween
response = handler(request)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_tm-0.10-py2.7.egg/pyramid_tm/__init__.py", line 95, in tm_tween
reraise(*exc_info)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_tm-0.10-py2.7.egg/pyramid_tm/__init__.py", line 83, in tm_tween
manager.commit()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_manager.py", line 111, in commit
return self.get().commit()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 280, in commit
reraise(t, v, tb)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 271, in commit
self._commitResources()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 417, in _commitResources
reraise(t, v, tb)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 389, in _commitResources
rm.tpc_begin(self)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/zope.sqlalchemy-0.7.5-py2.7.egg/zope/sqlalchemy/datamanager.py", line 90, in tpc_begin
self.session.flush()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/session.py", line 1919, in flush
self._flush(objects)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/session.py", line 2037, in _flush
transaction.rollback(_capture_exception=True)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/session.py", line 2001, in _flush
flush_context.execute()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/unitofwork.py", line 372, in execute
rec.execute(self)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/unitofwork.py", line 479, in execute
self.dependency_processor.process_deletes(uow, states)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/dependency.py", line 1023, in process_deletes
secondary_update, secondary_delete)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/dependency.py", line 1111, in _run_crud
result.rowcount)
StaleDataError: DELETE statement on table 'product_categories' expected to delete 1 row(s); Only 0 were matched.
Am I missing some sort of a 'gotcha' in this case? Seems like a pretty standard implementation. Why is it attempting to execute the DELETE statement twice?
After a bit more searching, I found the following link which suggests it's a MySQL bug:
https://groups.google.com/forum/#!topic/sqlalchemy/ajYLEuhEB9k
Thankfully, disabling supports_san_multi_rowcount helped!
engine = engine_from_config(settings, 'sqlalchemy.')
engine.dialect.supports_sane_rowcount = engine.dialect.supports_sane_multi_rowcount = False
Good enough for me for now. Here's another interesting resources I found along the way dealing with postgresql:
https://bitbucket.org/zzzeek/sqlalchemy/issue/3015/deletes-executed-twice-when-using

Categories