Hi can someone help with this sqlalchemy code. When i invoke this code, it throws this error
~/.local/lib/python3.8/site-packages/sqlalchemy/sql/base.py:425: SAWarning: Can't validate argument 'foreign_key'; can't locate any SQLAlchemy dialect named 'foreign'
util.warn(
Code follows:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class Users(Base):
__tablename__ = 'users'
email = Column(String, primary_key=True, nullable=False)
firstname = Column(String)
lastname = Column(String)
userid = Column(String, unique=True, nullable=False)
class Account(Base):
__tablename__ = 'account'
userid = Column(Integer, foreign_key='Users.userid', nullable=False)
internal_account_id = Column(Integer, primary_key=True, nullable=False)
account_id = Column(String, nullable=False)
Related
i cant get a simple query example of how to get record data based on the relationship,
models.py
from sqlalchemy import ForeignKey, Column, Integer, String, Boolean
from sqlalchemy.orm import relationship, declarative_base
Base = declarative_base()
class Category(Base):
__tablename__ = "category"
id = Column(Integer, primary_key=True)
wp_id = Column(Integer, nullable=False)
name = Column(String)
child_categories = relationship("Keyword", back_populates="parent_category", cascade="all, delete-orphan")
def __repr__(self):
return f"<wp id: {self.wp_id}, category name: {self.name}>"
class Keyword(Base):
__tablename__ = "keyword"
id = Column(Integer, primary_key=True)
wp_id = Column(Integer, unique=True)
name = Column(String)
questions = relationship("Question", back_populates="keyword", cascade="all, delete-orphan")
is_processed = Column(Boolean, nullable=True)
is_posted = Column(Boolean, nullable=True)
category_id = Column(String, ForeignKey('category.id'), nullable=True)
parent_category = relationship("Category", back_populates="child_categories")
def __repr__(self):
return f"<id: {self.wp_id}, keyword name: {self.name}>"
class Question(Base):
__tablename__ = "question"
id = Column(Integer, primary_key=True)
question = Column(String)
answer = Column(String)
keyword_id = Column(Integer, ForeignKey('keyword.id'), nullable=False)
keyword = relationship("Keyword", back_populates='questions')
def __repr__(self):
return f"<question: {self.question}>"
and i want all the keywords that are child of category with wp_id == 23
alot of the material in internet are either old, or are solutions for flask sqlalchemy, and there seems many ways to do one thing, thats why im a bit confused,
i tried the below:
wp_category_id = 23
def get_category_keywords_details(wp_category_id):
global engine
with Session(engine) as session:
keyword_details = session.execute(select(Keyword).where(Keyword.parent_category.wp_id ==
wp_category_id)).all()
which gave error:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Keyword.parent_category has an attribute 'wp_id'
SQLAlchemy script works fine with sqlite3 but when connected to MYSQL database it gives different errors like:
AttributeError: '_NoResultMetaData' object has no attribute '_indexes_for_keys'
sqlalchemy.exc.NoSuchColumnError: Could not locate column in row for column 'filters.id'
KeyError: Column('id', Integer(), table=, primary_key=True, nullable=False)
The functions works fine when running separately but when used with flask they raise above errors.
My DB models:
from sqlalchemy import Column, Integer, String, MetaData, Boolean, DateTime
from sqlalchemy.ext.declarative import declarative_base
import datetime
Base = declarative_base()
class ProfileData(Base):
__tablename__ = 'profile_data'
id = Column(Integer, primary_key=True)
user_id = Column("user_id", Integer)
user_profile_link = Column(String(100))
username = Column(String(100))
name = Column(String(100))
is_verified = Column(Boolean)
website = Column(String(100))
bio = Column(String(1000))
location = Column(String(100))
created_at = Column(DateTime)
followers = Column(Integer)
following = Column(Integer)
_datetime = Column(DateTime, default=datetime.datetime.utcnow)
Thanks in advance.
I would suggest to do this and this how usually do my setup
first init db object from SQLAlchemy
db = SQLAlchemy()
then declare the model using db.model
class ProfileData(db.Model):
__tablename__ = 'profile_data'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column("user_id", db.Integer)
user_profile_link = db.Column(db.String(100))
username = db.Column(db.String(100))
hope this fix your issue
I am new to Postgresql & Sqlalchemy. I have below file layout.py. In this, I have created two table name "layout" & "layout default" under "col" schemas.
import json, decimal
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy import create_engine
from sqlalchemy import Column, String, Integer, TIMESTAMP, Sequence, text, types
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import datetime, uuid
db_string = "postgres://postgres:PWDd#10.**.**.***:1111/d_demo"
Base = declarative_base()
db = create_engine(db_string)
class Layout(Base):
__tablename__ = "col.layout"
layout_id = Column(UUID(as_uuid=True), nullable=False, primary_key=True)
name = Column(String(1000), nullable=False)
layout = Column(String(10000), nullable=False)
grid_id = Column(Integer, nullable=False)
user_id = Column(Integer, nullable=False)
issystemlayout = Column(Integer, default=0, nullable=False)
ispublic = Column(Integer, default=0, nullable=False)
isactive = Column(Integer, default=0, nullable=False)
createdby = Column(Integer, default=1, nullable=False)
createdat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedby = Column(Integer, default=1, nullable=False)
Insert datas :
INSERT INTO col.layout(layout_id,name,layout,grid_id,user_id,ispublic,issystemlayout,isactive,createdby,createdat, modifiedat,modifiedby) VALUES('ba0233d7-d917-4303-b4bf-c2544a617d33','Layout1','{"Name":"Manish","Place":"Pune"}',1,12345,'1','0','1','201819','2015/05/20','2015/05/16',123);
Fetching data :
Session = sessionmaker(bind=db)
session = Session()
Base.metadata.create_all(db)
session.query("SET search_path TO col;")
result = []
selected_columns = Layout.__table__.columns
print("Selected columns {}".format(selected_columns))
record = session.query(Layout).with_entities(*selected_columns).all()
for row in record:
print(row)
result.append(row)
print(json.dumps(result))
session.close()
But it is not showing data under "col" schemas. Please suggest, how should I do?
https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/table_config.html#table-configuration
Schema for postgres database can be passed through table_args attribute either as a tuple or a dict.
So for your problem your class definition should have this extra attribute:
class Layout(Base):
__tablename__ = "layout"
__table_args__ = {"schema": "col"}
layout_id = Column(UUID(as_uuid=True), nullable=False, primary_key=True)
name = Column(String(1000), nullable=False)
layout = Column(String(10000), nullable=False)
grid_id = Column(Integer, nullable=False)
user_id = Column(Integer, nullable=False)
issystemlayout = Column(Integer, default=0, nullable=False)
ispublic = Column(Integer, default=0, nullable=False)
isactive = Column(Integer, default=0, nullable=False)
createdby = Column(Integer, default=1, nullable=False)
createdat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedat = Column(TIMESTAMP, default=(datetime.datetime.now()), nullable=False)
modifiedby = Column(Integer, default=1, nullable=False)
How can I create a many to many relationship using the models below:
class Association(Base):
a_id = Column(BigInteger, ForeignKey('a.id'), index=True)
b_id = Column(String, ForeignKey('b.some_other_id'))
class A(Base):
id = Column(BigInteger, primary_key=True)
class B(Base):
id = Column(BigInteger, primary_key=True)
some_other_id = Column(String(100), index=True, unique=True)
Adapting from SQLAlchemy documentation: You do not need to have the association model at all, if you do not need to have extra attributes for the association:
association_table = Table('association', Base.metadata,
Column('a_id', Integer, ForeignKey('a.id')),
Column('b_id', Integer, ForeignKey('b.some_id'))
)
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
b_s = relationship("B",
secondary=association_table,
backref="a_s")
class B(Base):
__tablename__ = 'b'
some_id = Column(Integer, primary_key=True)
Then b.a_s is a collection of A and a.b_s is a collection of B; changes therein will be reflected in the database on session.flush().
If you do want to have extra properties for the association between each A and B, then you can use the Association object pattern:
class Association(Base):
__tablename__ = 'association'
left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
extra_data = Column(String(50))
child = relationship("Child")
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Association")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
Use the relationship function of sqlalchemy.orm and make sure to declare a primary key in your join table.
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, ForeignKey, BigInteger, String
from sqlalchemy.orm import relationship
Base=declarative_base()
class Association(Base):
__tablename__='association'
a_id = Column(BigInteger, ForeignKey('a.id'), index=True, primary_key=True)
b_id = Column(String, ForeignKey('b.some_other_id'), primary_key=True)
class A(Base):
__tablename__='a'
id = Column(BigInteger, primary_key=True)
b_ids = relationship('B', secondary=Association)
class B(Base):
__tablename__='b'
id = Column(BigInteger, primary_key=True)
some_other_id = Column(String(100), index=True, unique=True)
a_ids = relationship('A', secondary=Association)
I have the following models. A user has many roles, and a role can have many permissions. I can't quite figure out how to query to get what I want.
user_role = db.Table(
'user_role',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('role_id', db.Integer, db.ForeignKey('role.id')),
db.UniqueConstraint('user_id', 'role_id')
)
role_permission = db.Table(
'role_permission',
db.Column('permission_id', db.Integer, db.ForeignKey('permission.id')),
db.Column('role_id', db.Integer, db.ForeignKey('role.id')),
db.UniqueConstraint('permission_id', 'role_id')
)
class Role(Base):
__tablename__ = 'role'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
class Permission(Base):
__tablename__ = 'permission'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
roles = db.relation(Role, secondary=role_permission, backref=db.backref('permissions'))
class User(Base, UserMixin):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(60), unique=True, nullable=False)
password_hash = db.Column(db.String(80), nullable=False)
roles = db.relation(Role, secondary=user_role, backref=db.backref('users'))
I want to get a (preferably unique) list of all the permissions assigned to a user, but I can't seem to figure out how to do it.
I can get the list by creating a generator in the User model:
def get_all_permissions(self):
for role in self.roles:
for perm in role.permissions:
yield perm
But I'd love to be able to do it in one query.
Well, to just get a list of the permissions, try something like this:
permissions = session.query(Permission).\
join(Role).join(User).filter(User.username='MisterX').all()
Or filter for whatever you want. To make the Permissions unique, you could use group by:
permissions = session.query(Permission.id, Permission.name).join(Role).join(User).\
filter(User.username='MisterX').group_by(Permission.id).all()
Or, without a special query, use the declarative extension, if you can:
permissions = User.roles.permissions
Does that help?
Possibly your association tables are not recognized properly, as you did not specify the metadata parameter. This script works for me:
#!/bin/python
from sqlalchemy import Table
from sqlalchemy import Integer, String, ForeignKey, create_engine, Column, PrimaryKeyConstraint
from sqlalchemy.orm import relationship, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()
user_role = Table(
'user_role',
Base.metadata,
Column('user_id', Integer, ForeignKey('users.id')),
Column('role_id', Integer, ForeignKey('roles.id')),
PrimaryKeyConstraint('user_id', 'role_id')
)
role_permission = Table(
'role_permission',
Base.metadata,
Column('permission_id', Integer, ForeignKey('permissions.id')),
Column('role_id', Integer, ForeignKey('roles.id')),
PrimaryKeyConstraint('permission_id', 'role_id')
)
class Role(Base):
__tablename__ = 'roles'
id = Column(Integer, primary_key=True)
name = Column(String(100), unique=True, nullable=False)
class Permission(Base):
__tablename__ = 'permissions'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False)
roles = relationship("Role", secondary=role_permission, backref=backref('permissions'))
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(60), unique=True, nullable=False)
password_hash = Column(String(80), nullable=False)
roles = relationship("Role", secondary=user_role, backref=backref('users'))
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
u = User(username="user", password_hash="secret")
r1 = Role(name="Role 1")
session.add(r1)
r2 = Role(name="Role 2")
session.add(r2)
p1 = Permission(name="Permission 1")
p2 = Permission(name="Permission 2")
p3 = Permission(name="Permission 3")
r1.permissions.append(p1)
r1.permissions.append(p2)
r2.permissions.append(p2)
r2.permissions.append(p3)
u.roles.append(r1)
u.roles.append(r2)
session.add(u)
for perm in session.query(Permission).join(Role, Permission.roles).\
join(User, Role.users).filter(User.username=="user").distict()all():
print(perm.name)
If you have loaded User object already into memory together with Permissions and Roles, you code should do it quickly and without going to a database.
Otherwise, this query should work:
user_id = 789
permissions = (db.session.query(Permission)
.join(Role, Permission.roles)
.join(User, Role.users)
.filter(User.id == user_id)
).distinct()
#print(permissions)
for perm in permissions:
print(perm)