ArgumentError: Mapper mapped class Roles_users->User Roles could not assemble any primary key columns for mapped table 'User Roles' - roles

I'm trying to write a web app with user roles and I keep getting this error no matter the changes I make.
Could you please help me find what's wrong?
Thank you in advance!!
This is my models.py file:
from sqlalchemy import Column, Integer, String, Float, Boolean, ForeignKey
from flask_login import UserMixin
from sqlalchemy.orm import relationship, backref
import db
class Rol(db.Base):
__tablename__ = 'Roles'
id_rol = Column(Integer, primary_key=True)
nombre_rol = Column(String, nullable=False)
user_rol = relationship("User rol", back_populates="rol", uselist =False)
def __init__(self, nombre_rol):
self.nombre_rol = nombre_rol
class User(UserMixin, db.Base):
__tablename__ = 'Users'
user_id = Column(Integer, primary_key=True)
username = Column(String, unique=True, nullable=False)
password = Column(String, unique=True, nullable=False)
is_active = Column(Boolean, default=False)
user_rol = relationship("User rol", back_populates="user", uselist =False)
def __init__(self,username,password,is_active):
self.username = username
self.password = password
self.is_active = is_active
def get_id(self):
return self.id
def is_active(self):
return self.is_active
def activate_user(self):
self.is_active = True
def get_username(self):
return self.username
def get_rol(self):
return self.rol
class Roles_users(db.Base):
__tablename__ = 'User Roles'
user_id = Column(Integer, ForeignKey("Users.user_id"))
id_rol = Column(Integer, ForeignKey("Roles.id_rol"))
user = relationship("User", back_populates="user roles")
rol = relationship("Rol", back_populates="user roles")

Related

How do I check if many-to-many row already exists in sqlalchemy to prevent duplicate?

Here is code for my models:
class IllustratorAsset(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
uploader = db.Column(db.Integer, db.ForeignKey('user.id'))
project = db.Column(db.Integer, db.ForeignKey('project.id'))
fragments = db.relationship('AssetFragment', backref='ai', lazy='dynamic')
file_hash = db.Column(db.String(128), unique=True)
file_name = db.Column(db.String(128))
def __repr__(self):
return '<Picture {}>'.format(self.id)
tags_association = db.Table(
'tags_association',
db.Column('fragment_id', db.Integer(), db.ForeignKey('asset_fragment.id'),index=True),
db.Column('tag_id', db.Integer(), db.ForeignKey('tag.id'),index=True),
PrimaryKeyConstraint('fragment_id', 'tag_id')
)
class AssetFragment(db.Model):
id = db.Column(db.Integer, primary_key=True)
asset = db.Column(db.Integer, db.ForeignKey('illustrator_asset.id'))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
uploader = db.Column(db.Integer, db.ForeignKey('user.id'))
tags = db.relationship('Tag', secondary=tags_association, backref='fragments', lazy='dynamic')
file_name = db.Column(db.String(128))
file_hash = db.Column(db.String(128))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
tag = db.Column(db.String(64), index=True, unique=True)
def __repr__(self):
return '<Tag {}>'.format(self.tag)
The idea is illustrations storage, there is Asset (Adobe Illustrator file), it has Fragments (renders of its different fragments), the fragment has some Tags for quick search which should be working through many-to-many relationship tags_association.
Currently, I'm stuck at trying to check if an association already exists, I'm sure there is some simple way to do it, but I'm missing some point. I came up with the code below, and I still get the exception of constraints.
for tag in new_tags: #list of tags from form
t = Tag.query.filter_by(tag=tag).first()
if (t is not None) and not(t in fragment.tags):
fragment.tags.append(t)
else:
new_tag = Tag(tag=tag)
if not(new_tag in fragment.tags):
fragment.tags.append(new_tag)
DB is Postgres
Well answer came shortly after I've tried to do it in flask shell. Shell output
I've realized, that it seems to be something wrong with the comparator, simple override makes it work:
def __eq__(self, __o: object) -> bool:
return self.tag == __o.tag
Also needed to change checking by a bit:
for tag in new_tags:
t = Tag.query.filter_by(tag=tag).first()
if t is None:
new_tag = Tag(tag=tag)
print(new_tag)
if not(new_tag in fragment.tags):
fragment.tags.append(new_tag)
else:
print(t)
if not(t in fragment.tags):
fragment.tags.append(t)

sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed

I am trying to create table for some courses, wհօse last column is another table and presents the lecturers names.
class Teachers(Base):
__tablename__ = 'teacher'
full_name = Column(String, unique=False, primary_key=True)
company = Column(String, unique = False)
class Course(Base):
__tablename__ = 'course'
course_name = Column(String, nullable=False)
course_id = Column(String,primary_key=True)
level = Column(String,unique=False)
teachers = Teachers
But I found following issue when the name of one lecturer is repeated in different courses:
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: teacher.full_name
How can I solve this problem?
Your teachers column is not a column. Instead you are adding a whole table as an attribute.
What you should do, is defining a column in Course that contains the primary key of the Teacher (assuming there is only one teacher per course) and mark it as a ForeignKey. You can than also add a relationship for easier work.
from pathlib import Path
import sqlalchemy.orm
from sqlalchemy import Column, String, ForeignKey, create_engine
from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class Teacher(Base):
__tablename__ = "teachers"
full_name = Column(String, unique=False, primary_key=True)
company = Column(String, unique=False)
class Course(Base):
__tablename__ = "courses"
course_id = Column(String, primary_key=True)
course_name = Column(String, nullable=False)
level = Column(String, unique=False)
teacher_name = Column(ForeignKey("teachers.full_name"))
teacher = relationship("Teacher")
def main():
if Path("test_database.db").exists():
Path("test_database.db").unlink()
engine = create_engine("sqlite:///test_database.db")
Base.metadata.create_all(engine)
session = sqlalchemy.orm.Session(autocommit=False, autoflush=False, bind=engine)
teacher_1 = Teacher(full_name="Bob")
course_1 = Course(course_id=1, course_name="Course 1", level="beginner", teacher=teacher_1)
course_2 = Course(course_id=2, course_name="Course 2", level="advanced", teacher=teacher_1)
session.add_all([course_1, course_2])
session.commit()
if __name__ == "__main__":
main()

Issue when creating on-to-many relationships in SQLAlchemy database

I created a Flask app with a database, with following classes:
db = SQLAlchemy(app)
class Category(db.Model):
__tablename__ = 'Category'
children = relationship("Child")
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.Text())
icon = db.Column(db.Text())
subcategories = db.relationship('Subcategory', backref="category")
def __init__(self, name, subcategories, icon):
self.name = name
self.color = icon
self.subcategories = subcategories
class Subcategory(db.Model):
__tablename__ = 'Subcategory'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.Text())
color = db.Column(db.Text())
reward_points = db.Column(db.Integer())
category = db.Column(db.Text())
tasks = db.relationship('Task', backref="subcategory")
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
def __init__(self, name, color, reward_points, category, tasks, category_id):
self.name = name
self.color = color
self.reward_points = reward_points
self.category = category
self.tasks = tasks
self.category_id = category_id
class Task(db.Model):
__tablename__ = 'Task'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
task = db.Column(db.Text())
start = db.Column(db.DateTime())
end = db.Column(db.DateTime())
duration = db.Column(db.Integer)
scheduled = db.Column(db.DateTime())
created = db.Column(db.DateTime())
status = db.Column(db.Text())
category = db.Column(db.Text())
subcategory = db.Column(db.Text())
tags = db.Column(db.Text())
subcategory_id = db.Column(db.Integer, db.ForeignKey('subcategory.id'))
def __init__(self, task, start, end, duration, category, subcategory, tags, created, status, scheduled, subcategory_id):
self.task = task
self.start = start
self.end = end
self.duration = duration
self.category = category
self.subcategory = subcategory
self.tags = tags
self.created = created
self.status = status
self.scheduled = scheduled
self.subcategory_id = subcategory_id
My goal is to create one to many relationships between the classes. I am trying to run the db.create_all() command, but am getting following error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'Subcategory.category_id' could not find table 'category' with which to generate a foreign key to target column 'id'
What am I doing wrong? Other questions on Stackoverflow with similar issues did not resolve my error.
Changing
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
to
category_id = db.Column(db.Integer, db.ForeignKey('Category.id'))
solved the issue.
Changing "category.id" to "category.c.id" solved the issue as well. If anyone knows why, pls let me know ;-)

How to add a self increased field by category

I want to set a sub id for my post table. This table already has a id field as primary. But post has categories. I want a sub_id for post in each category as self increased.
I am writing my blog. Post is has PostCategory, PostCategory to Post is one-to-many relationship.
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
# I tried this, but this did not work
sub_id = db.Column(db.Integer, nullable=True, default=int(f'select count(*) from post where category_id={category_id}')+1)
title = db.Column(db.String(120), unique=True, nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
# user in Foreignkey is table name
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('post_category.id'), nullable=False)
def post_content_render_markdown(self):
return markdown(self.content, extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
])
def __repr__(self):
return f"Post('{self.title}', {self.category.name}, '{self.date_posted}')"
class PostCategory(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), unique=True, nullable=False)
description = db.Column(db.Text, nullable=False)
posts = db.relationship('Post', backref='category', lazy=True)
def __repr__(self):
return f"Post Category('{self.id}', '{self.name}')"
error msg
sub_id = db.Column(db.Integer, nullable=True, default=int(f'select count(*) from post where category_id={category_id}')+1)
NameError: name 'category_id' is not defined
There is an another existing argument that can increase your sub_id
https://docs.sqlalchemy.org/en/13/core/defaults.html#python-executed-functions
sub_id = db.Column(db.Integer, nullable=True, autoincrement=True)
Try this

SQL Alchemy query multiple tables

I am trying to make a query using SQL alchemy which would otherwise been very simple if I wasn't using ORM, so I am thinking to myself surely there must be a straightforward way. I have gone through most of the questions on this topic but don't seem to answer my question. I have these two tables
class Artisan(Base):
__tablename__ = 'artisan'
name = Column(String(80), nullable=False)
skill = Column(String(80), nullable=False)
id = Column(Integer, primary_key=True)
bio = Column(String(300))
category = Column(Integer, ForeignKey(Category.id))
user = Column(Integer, ForeignKey(Users.id))
id_no = Column(Integer, nullable=False)
users = relationship(Users)
and
class Address(Base):
__tablename__ = 'address'
building = Column(String(80), nullable=False)
floor = Column(String(80), nullable=False)
house_no = Column(String(80), nullable=False)
telephone = Column(String(80), nullable=False)
kwetu_address = Column(String(80), nullable=False)
id = Column(Integer, primary_key=True)
lat = Column(String(25))
lng = Column(String(25))
artisan = Column(Integer, ForeignKey(Artisan.id))
user = Column(Integer, ForeignKey(Users.id))
users = relationship(Users)
I would like to filter the Artisans by a category, then filter the addresses by the filtered artisans, and present the results in a way that associates the artisan with respective addresses hopefully getting sqlachemy to do the filtering
The best I can come up with involves two queries and post processing which I feel is very inefficient
my_artisans = (session.query(Artisan).filter_by(category=cat_id))
my_addresses = (session.query(Address)
.join(Artisan, Artisan.id ==Address.artisan).filter_by(category=cat_id))
return jsonify(artisans =[art.serialize for art in my_artisans], addresses=[add.serialize for add in my_addresses])
Thanks
Add on - all related classes
import sys
from sqlalchemy import Column, ForeignKey, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine
Base = declarative_base()
class Users(Base):
__tablename__ = 'users'
name = Column(String(80), nullable=False)
email = Column(String(80), nullable=False)
id = Column(Integer, primary_key=True)
bio = Column(String(300))
picture = Column(String(80))
class Category(Base):
__tablename__ = 'category'
name = Column(String(80), nullable=False)
id = Column(Integer, primary_key=True)
user = Column(Integer, ForeignKey(Users.id))
users = relationship(Users)
#property
def serialize(self):
return{
'id': self.id,
'name': self.name
}
class Artisan(Base):
__tablename__ = 'artisan'
name = Column(String(80), nullable=False)
skill = Column(String(80), nullable=False)
id = Column(Integer, primary_key=True)
bio = Column(String(300))
category = Column(Integer, ForeignKey(Category.id))
user = Column(Integer, ForeignKey(Users.id))
id_no = Column(Integer, nullable=False)
users = relationship(Users)
#property
def serialize(self):
return{
'id': self.id,
'name': self.name,
'skill': self.skill,
'category': self.category,
'bio': self.bio,
'id_no': self.id_no
}
class Portfolio(Base):
__tablename__ = 'portfolio'
title = Column(String(80), nullable=False)
details = Column(String(300), nullable=False)
id = Column(Integer, primary_key=True)
artisan = Column(Integer, ForeignKey(Artisan.id))
user = Column(Integer, ForeignKey(Users.id))
users = relationship(Users)
#property
def serialize(self):
return{
'id': self.id,
'title': self.title,
'details': self.details
}
class Endorsements(Base):
__tablename__ = 'endorsements'
title = Column(String(80), nullable=False)
details = Column(String(300), nullable=False)
id = Column(Integer, primary_key=True)
artisan = Column(Integer, ForeignKey(Artisan.id))
user = Column(Integer, ForeignKey(Users.id))
users = relationship(Users)
#property
def serialize(self):
return{
'id': self.id,
'title': self.title,
'details': self.details
}
class Address(Base):
__tablename__ = 'address'
building = Column(String(80), nullable=False)
floor = Column(String(80), nullable=False)
house_no = Column(String(80), nullable=False)
telephone = Column(String(80), nullable=False)
kwetu_address = Column(String(80), nullable=False)
id = Column(Integer, primary_key=True)
lat = Column(String(25))
lng = Column(String(25))
artisan = Column(Integer, ForeignKey(Artisan.id))
user = Column(Integer, ForeignKey(Users.id))
users = relationship(Users)
#property
def serialize(self):
return{
'id': self.id,
'lat': self.lat,
'lng': self.lng,
'kwetu_address': self.kwetu_address,
'artisan': self.artisan
}
engine = create_engine('sqlite:///mycatalog.db')
Base.metadata.create_all(engine)
This gave me what I needed in terms of associating my artisan with respective addresses, though still using two queries
my_artisans = (session.query(Artisan).filter_by(category=cat_id))
my_addresses = (session.query(Address)
.join(Artisan, Artisan.id ==Address.artisan).filter_by(category=cat_id))
these_addresses = []
for art in my_artisans:
art_id = art.id
for add in my_addresses:
if art_id == add.artisan:
grouped_address = {"Artisan Id" : art.id, "name" : art.name, "skill" : art.skill, "Lat" : add.lat, "lng" : add.lng}
these_addresses.append(grouped_address)
return jsonify({'Addresses': these_addresses })