I am trying to get all rows from a table.
In controller I have:
meta.Session.query(User).all()
The result is [, ], but I have 2 rows in this table.
I use this model for the table:
import hashlib
import sqlalchemy as sa
from sqlalchemy import orm
from allsun.model import meta
t_user = sa.Table("users",meta.metadata,autoload=True)
class Duplicat(Exception):
pass
class LoginExistsException(Exception):
pass
class EmailExistsException(Exception):
pass
And next, in the same file:
class User(object):
def loginExists(self):
try:
meta.Session
.query(User)
.filter(User.login==self.login)
.one()
except orm.exc.NoResultFound:
pass
else:
raise LoginExistsException()
def emailExists(self):
try:
meta
.Session
.query(User)
.filter(User.email==self.email)
.one()
except orm.exc.NoResultFound:
pass
else:
raise EmailExistsException()
def save(self):
meta.Session.begin()
meta.Session.save(self)
try:
meta.Session.commit()
except sa.exc.IntegrityError:
raise Duplicat()
orm.mapper(User, t_user)
You can easily import your model and run this:
from models import User
# User is the name of table that has a column name
users = User.query.all()
for user in users:
print user.name
I use the following snippet to view all the rows in a table. Use a query to find all the rows. The returned objects are the class instances. They can be used to view/edit the values as required:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Sequence
from sqlalchemy import String, Integer, Float, Boolean, Column
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class MyTable(Base):
__tablename__ = 'MyTable'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
some_col = Column(String(500))
def __init__(self, some_col):
self.some_col = some_col
engine = create_engine('sqlite:///sqllight.db', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
for class_instance in session.query(MyTable).all():
print(vars(class_instance))
session.close()
Related
I wrote an application using SQLAlchemy's object relational mapper to store and access data from an SQLite3 database.
I can call add_userto add one or multiple users and call get_users to get them
I can import data from excel and get them with get_users
I can import data from excel and add a user with add_user
BUT I can't get the users with the get_users function afterwards, because I'm getting the following error for the entry created with add_user: AttributeError: 'NoneType' object has no attribute 'id'
What am I doing wrong?
Here's a simple version of the application:
orm_test.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
def orm_setup():
Base = declarative_base()
engine = create_engine('sqlite:///:main:', echo=True)
Base.metadata.create_all(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()
return Base, engine, session
orm_test_class.py
from sqlalchemy import Column, Integer, String
from orm_test import orm_setup
Base = orm_setup()[0]
engine = orm_setup()[1]
class User(Base):
__tablename__ = 'person'
id = Column('id', Integer, primary_key=True)
username = Column('username', String, unique=True)
Base.metadata.create_all(bind=engine)
orm_test_functions.py
from orm_test_class import User
from orm_test import orm_setup
session = orm_setup()[2]
def add_user(name):
u = User()
user_name = str(name)
u.username = user_name
session.add(u)
session.commit()
def get_users():
users = session.query(User).all()
for user in users:
print(user.id, user.username)
session.close()
main.py
import fire
from orm_test_functions import add_user, get_users
if __name__ == '__main__':
fire.Fire()
data_import.py
import fire
import pandas as pd
from orm_test import orm_setup
# import engine from orm
engine = orm_setup()[1]
def data_import():
file = 'Data.xlsx'
df_user = pd.read_excel(file, sheet_name = 'User')
df_user.to_sql('person', engine, if_exists='replace', index=False)
# Command line interface
if __name__ == '__main__':
fire.Fire()
The problem is that df_to_sql drops the original table, which has a primary key defined, and replaces it with a table that does not define a primary key.
From the dataframe_to_sql docs
replace: Drop the table before inserting new values.
You can get around this by setting if_exists='append' instead of if_exists='replace'.
df_user.to_sql('person', engine, if_exists='append', index=False)
If necessary you can emulate the "replace" behaviour by deleting any existing records from the table before importing the data.
This is the code I used to reproduce and resolve:
import io
import sqlalchemy as sa
from sqlalchemy import orm
import pandas as pd
Base = orm.declarative_base()
class User(Base):
__tablename__ = 'person'
id = sa.Column('id', sa.Integer, primary_key=True)
username = sa.Column('username', sa.String, unique=True)
engine = sa.create_engine('sqlite://', echo=True, future=False)
# Drop all is redundant for in-memory db
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
sessionmaker = orm.sessionmaker(engine)
def add_user(name):
session = sessionmaker()
u = User()
user_name = str(name)
u.username = user_name
session.add(u)
session.commit()
def get_users():
session = sessionmaker()
users = session.query(User).all()
for user in users:
print(user.id, user.username)
print()
session.close()
DATA = """\
id,username
1,Alice
2,Bob
"""
buf = io.StringIO(DATA)
df_user = pd.read_csv(buf)
df_user.to_sql('person', engine, if_exists='append', index=False)
users = get_users()
add_user('Carol')
users = get_users()
engine.dispose()
You should set the column id with AUTOINCREMENT keyword, see https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#using-the-autoincrement-keyword
This question already has answers here:
Foreign key contraint is not getting set in SQLlite using flask alchemy [duplicate]
(1 answer)
SQLite3 "forgets" to use foreign keys
(3 answers)
Closed 1 year ago.
With the code below and following sequence I suspect an IntegrityError with a Foreign Key violation. Unfortunately the error isn't raised.
Create Customer(id=1)
Create Booking(cid=1)
Delete Customer(id=1)
#main.py
from typing import List
from fastapi.params import Depends
from schemas import Customer, ShowCustomer, Booking, ShowBooking
from fastapi import FastAPI, HTTPException
from database import get_db, engine, Base
from sqlalchemy.orm import Session
import models
models.Base.metadata.create_all(engine)
app = FastAPI()
#app.post("/customer")
async def customer(req: Customer, db: Session=Depends(get_db)):
new_customer=models.Customer(name=req.name, type=req.type)
db.add(new_customer)
db.commit()
db.refresh(new_customer)
return new_customer
#app.get("/customer", response_model=List[ShowCustomer])
async def create(db: Session=Depends(get_db)):
customers=db.query(models.Customer).all()
return customers
#app.delete('/customer/{id}')
def destory(id, db: Session=Depends(get_db)):
customer=db.query(models.Customer).filter(models.Customer.id == id)
if not customer.first():
raise HTTPException(status_code=404,
detail=f'Blog with the id {id} is not available '
)
customer.delete(synchronize_session=False)
db.commit()
return 'done'
#app.post("/booking")
async def read_root(req: Booking, db: Session=Depends(get_db)):
new_booking=models.Booking(name=req.name, type=req.type, cid=1)
db.add(new_booking)
db.commit()
db.refresh(new_booking)
return new_booking
#app.get("/booking",response_model=List[ShowBooking])
async def read_root(db: Session=Depends(get_db)):
bookings=db.query(models.Booking).all()
return bookings
# schemas.py
from pydantic import BaseModel
class Customer(BaseModel):
name:str
type:str
class ShowCustomer(Customer):
id:int
class Config():
orm_mode = True
class Booking(BaseModel):
name:str
type:str
class ShowBooking(Booking):
id:int
cid:int
class Config():
orm_mode = True
#models.py
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from database import Base
class Customer(Base):
__tablename__ = "customers"
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
type = Column(String)
booking = relationship("Booking", back_populates="customer")
class Booking(Base):
__tablename__ = "bookings"
id = Column(Integer, primary_key=True, index=True)
cid = Column(Integer, ForeignKey("customers.id"), nullable=False)
name = Column(String)
type = Column(String)
customer = relationship('Customer', back_populates="booking")
#database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
SQLALCHEMY_DATABASE_URL = 'sqlite:///./cloud2.db'
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
Base = declarative_base()
def get_db():
db=SessionLocal()
try:
yield db
finally:
db.close()
I'm trying to save a list of custom objects with sqlalchemy:
session.bulk_save_objects(listOfObjects)
And obtaining IntegrityError:
psycopg2.IntegrityError: duplicate key value violates unique constraint "ppoi_ukey"
And:
Key ("id")=(42555) already exists.
Is there any way to get the key Id (42555) as an integer, in order to roll back, extract this key from the list, and re insert the list again without it?
I tried something which I think might help you.
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import IntegrityError
Base = declarative_base()
#Create a dummy model
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String(250), nullable=False)
def __repr__(self):
return "{ id="+str(self.id)+", name="+self.name+ " }"
# Create an engine that stores data in the local directory's
# sqlalchemy_example.db file.
engine = create_engine('sqlite:///sqlalchemy_example.db')
# Create all tables
Base.metadata.create_all(engine)
DBSession = sessionmaker(bind=engine)
session = DBSession()
list_of_objects = []
new_person = Person(id=1,name='new person')
list_of_objects.append(new_person)
new_person2 = Person(id=2,name='new person2')
list_of_objects.append(new_person2)
# Violating unique constraint purposely
new_person3 = Person(id=1,name='new person')
list_of_objects.append(new_person3)
print(list_of_objects)
for person in list_of_objects:
# with session.no_autoflush:
try:
session.add(person)
session.commit()
except IntegrityError as e:
session.rollback()
#print(e) #prints whole exception
print(e.params) #print lists of param to the query
print(e.params[0]) #assuming the first param is unique id which is violating constraint you can get it from here and use it as you wanted ..
except Exception as ex:
pass
person = session.query(Person).all()
print(len(person)) #returns 2
Is it possible to instance a table with its tablename?
I've looked for in SQLAlchemy documentation and I couldn't find anything.
class A():
__tablename__ = 'x'
newTable = Table('x')
Is possible something like this?
This is a pseudo-language, not real Python code
Thanks,
Create_a.py
import os
import sys
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine
Base = declarative_base()
class A(Base):
__tablename__ = 'X'
A_id = Column(Integer, primary_key=True)
A_name = Column(String(250), nullable=False)
engine = create_engine('sqlite:///sqlalchemy_example.db')
Base.metadata.create_all(engine)
Insert_a.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from Create_a import A, Base, engine
Base.metadata.bind = engine
DBSession = sessionmaker(bind=engine)
session = DBSession()
print A.__tablename__
A.__tablename__ = A
new_A = A.__tablename__(A_name='new A')
session.add(new_A)
session.commit()
Were A.__tablename__ is X
Given some model Foo:
class Foo(Base):
__tablename__ = 'foos'
...
the associated table object can be accessed directly via the __table__ attribute (provided that the entity has been mapped, for example via Base.metadata.create_all):
tbl = Foo.__table__
If only the value of Foo.__tablename__ is available the table can be retrieved using reflection:
tbl = sa.Table('foos', sa.MetaData(), autoload_with=engine)
I have a SQLAlchemy table class created using the Declarative method:
mysqlengine = create_engine(dsn)
session = scoped_session(sessionmaker(bind=mysqlengine))
Base = declarative_base()
Base.metadata.bind = mysqlengine
class MyTable(Base):
__table_args__ = {'autoload' : True}
Now, when using this table within the code I would like to not have to use the session.add method in order to add each new record to the active session so instead of:
row = MyTable(1, 2, 3)
session.add(row)
session.commit()
I would like to have:
row = MyTable(1, 2, 3)
session.commit()
Now, I know of this question already: Possible to add an object to SQLAlchemy session without explicit session.add()?
And, I realize you can force this behavior by doing the following:
class MyTable(Base):
def __init__(self, *args, **kw):
super(MyTable, self).__init__(*args, **kw)
session.add(self)
However, I do not want to bloat my code containing 30 tables with this method. I also know that Elixir ( http://elixir.ematia.de/trac/wiki ) does this so it must be possible in some sense.
Super simple. Use an event:
from sqlalchemy import event, Integer, Column, String
from sqlalchemy.orm import scoped_session, sessionmaker, mapper
from sqlalchemy.ext.declarative import declarative_base
Session = scoped_session(sessionmaker())
#event.listens_for(mapper, 'init')
def auto_add(target, args, kwargs):
Session.add(target)
Base = declarative_base()
class A(Base):
__tablename__ = "a"
id = Column(Integer, primary_key=True)
data = Column(String)
a1 = A(data="foo")
assert a1 in Session()