I am beginner trying to make a relational database in Flask project using SQLalchemy
This is the error that I am getting when I try to register a user:-
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Question->question, expression 'Answer' failed to locate a name ('Answer'). If this is a class name, consider adding this relationship() to the <class 'nothingness.models.Question'> class after both dependent classes have been defined.
DB relationships are:-
User (Many to Many) Table
User (1 to Many) Question
Question (1 to Many) Answer
Table (1 to Many) Question
Here are my codes
from datetime import datetime
from nothingness import db
members = db.Table(
"member",
db.Column("id", db.Integer, primary_key=True),
db.Column("table_id", db.Integer, db.ForeignKey("table.id")),
db.Column("user_id", db.Integer, db.ForeignKey("user.id")),
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(25), unique=True, nullable=False)
name = db.Column(db.String(25), nullable=False)
email = db.Column(db.String(), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default="default.jpg")
password = db.Column(db.String(60), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
member = db.relationship("Table", secondary=members, backref=db.backref("members", lazy=True))
prashna = db.relationship("Question", backref="user", lazy=True)
def __repr__(self):
return f"User('{self.name}', '{self.username}', '{self.email}', '{self.image_file}')db.Model"
class Table(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(25), nullable=False)
key = db.Column(db.String(5), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
question = db.relationship("Question", backref="questions", lazy=True)
def __repr__(self):
return f"Table('{self.id}', '{self.name}', '{self.key}', {self.created_at})"
class Question(db.Model):
id = db.Column(db.Integer, primary_key=True)
question = db.Column(db.String(255), nullable=False)
asked_by = db.Column(db.Integer, db.ForeignKey("user.id"))
asked_to = db.Column(db.Integer, nullable=False)
answer = db.relationship("Answer", backref="question", lazy=True)
table = db.Column(db.Integer, db.ForeignKey("table.id"))
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
class Answer:
id = db.Column(db.Integer, primary_key=True)
points = db.Column(db.Integer)
answer = db.Column(db.String(255), nullable=False)
answered_by = db.Column(db.Integer, nullable=False)
table_id = db.Column(db.Integer, nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
question = db.Column(db.Integer, db.ForeignKey("question.id"))
def __repr__(self):
return f"Answer('{self.points}', '{self.answer}', '{self.created_at}')"
This error occurred because I forgot to subclass Answer with db.Model
Related
Cannot save record to my db.
I created endpoint which makes user and saves him to db:
#router.post("/user/register/", tags=['user'], status_code=201)
async def user_register_web(user: RegisterWebSchema, db: Session = Depends(get_db)):
if user.password != user.password_repeat:
raise HTTPException(status_code=404, detail="Passwords dont match each other!")
db_user = UserModel(name=user.name.title(), surname=user.surname.title(), email=user.email,
phone_number=user.phone_number, login=user.login, password=user.password,
photo=None, is_admin=False, coins=0)
db.add(db_user)
db.commit()
db.refresh(db_user)
return {"JWT Token": signJWT(user.email),
**user.dict()}
Here is model of my User:
class User(Base):
__tablename__ = "user"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, index=True)
name = Column(String(50), nullable=False)
surname = Column(String(50), nullable=False)
email = Column(String(50), unique=True, nullable=False)
phone_number = Column(String(15), unique=True, nullable=False)
login = Column(String(50), unique=True, nullable=False)
password = Column(String(80), nullable=False)
photo = Column(String(80), nullable=True)
is_admin = Column(Boolean, nullable=False)
coins = Column(Integer, nullable=False)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
address_id = Column(Integer, ForeignKey("address.id"), nullable=False)
address = relationship("Address", back_populates="user")
pin = relationship("Pin", back_populates="user")
payment_card = relationship("PaymentCard", back_populates="user")
order = relationship("Order", back_populates="user")
feedback = relationship("Feedback", back_populates="user")
post = relationship("Post", back_populates="user")
comment = relationship("Comment", back_populates="user")
animal = relationship("Animal", back_populates="user")
walk = relationship("Walk", back_populates="user")
and here is the error I get:
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Order->order, expression 'Status' failed to locate a name ('Status'). If this is a class name, consider adding this relationship() to the <class 'database.models.OrderModel.Order'> class after both dependent classes have been defined.
model of Order:
class Order(Base):
__tablename__ = "order"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, index=True)
order_code = Column(String(15), nullable=True)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
status_id = Column(Integer, ForeignKey("status.id"), nullable=False)
status = relationship("Status", back_populates="order")
payment_method_id = Column(Integer, ForeignKey("payment_method.id"), nullable=False)
payment_method = relationship("PaymentMethod", back_populates="order")
user_id = Column(Integer, ForeignKey("user.id"), nullable=False)
user = relationship("User", back_populates="order")
post_office = relationship("PostOffice", back_populates="order")
product = relationship("Product", secondary=OrderProduct, back_populates="order")
and model of Status:
class Status(Base):
__tablename__ = "status"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), nullable=False)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
order = relationship("Order", back_populates="status")
I createrd migration successfully and then db. I dont understand why it shows lack of relationship, which i created. And it appears in lines of codes which dont even use these Tables.
In order to make it work I had to import all of my modules into api file with endpoint. I don't know why but it works right now.
I am trying to connect the id in the user class to the user_id in task class. I read the documentation from sqlalchemy and I have a hard time understanding the db.relationship part. I have also encountered a problem when updating the tables, when I ran db.create_all() in the terminal, these classes wasn't updated (it previously worked). Is this because the relational database I set up was wrong?
Here is my classes
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False, unique=True)
password = db.Column(db.String(80), nullable=False)
class Task(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
description = db.Column(db.Text)
complete =db.Column(db.Boolean, default=False)
And here is the documentation example
class Category(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
# Post table (in app/models/post.py)
class Post(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80))
body = db.Column(db.Text)
pub_date = db.Column(db.DateTime, default=datetime.utcnow)
# One to many relationship
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
category = db.relationship('Category', backref=db.backref('posts'))
Any answers or opinions will be greatly appreciated, thankyou.
These are my User and Role models:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
firstname = db.Column(db.String(100), nullable=False, server_default='')
lastname = db.Column(db.String(100), nullable=False, server_default='')
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
answers = db.relationship('Answer', backref="examinee", lazy=True)
date_created = db.Column(db.DateTime, default=datetime.utcnow)
active = db.Column('is_active', db.Boolean(), nullable=False, server_default='0')
roles = db.relationship('Role', secondary='user_roles', backref=db.backref('users', lazy='dynamic'))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True, autoincrement=True)
name = db.Column(db.String(50), unique=True)
description = db.Column(db.String(255))
class UserRoles(db.Model):
id = db.Column(db.Integer(), primary_key=True, autoincrement=True)
user_id = db.Column(db.Integer(), db.ForeignKey('user.id', ondelete='CASCADE'))
role_id = db.Column(db.Integer(), db.ForeignKey('role.id', ondelete='CASCADE'))
UniqueConstraint('user_id', 'role_id', name='user_role_uniqueness')
How can I remove all users with specific role such as 'student'?
I have tried the following snippet which did not work:
#app.route('/removeAllStudentUsers', methods=['GET', 'POST'])
def remove_all_student_users():
default_role_name = "student"
default_role = Role.query.filter(Role.name == default_role_name).first()
User.query.filter().delete(and_(User.roles.contains(default_role), func.count(User.roles) == 1)) # this line causes the error
db.session.commit()
return redirect(url_for('users'))
The above code causes this error:
sqlalchemy.exc.ArgumentError: Valid strategies for session synchronization are 'evaluate', 'fetch', False
There are multiple issues with your attempt to achieve that, including the fact that you might need a group by in order to check the count of the roles.
I would implement this a following:
_ = (
User.query
.filter(User.roles.any(Role.name == default_role_name)) # 1
.filter(~User.roles.any(Role.name != default_role_name)) # 2
.delete(synchronize_session=False) # 3
)
where:
makes sure to return only those User who has the given role
makes sure to exclude the User who has also other roles (this is what you try to solve with func.count)
this is the solution for the error you get.
I have the following database model:
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(20), unique=True, nullable=False)
password = db.Column(db.String(30), nullable=False)
email = db.Column(db.String(100), nullable=False, unique=True)
adverts = db.relationship('Advert', backref='autor', lazy=True)
messages_sent = db.relationship('Message',foreign_keys='Message.sender_id', backref='author', lazy='dynamic')
messages_received = db.relationship('Message',foreign_keys='Message.recipient_id', backref='recipient', lazy='dynamic')
telephone = db.Column(db.String(15))
def __repr__(self):
return f"User('{self.username}', '{self.email}'"
class Advert(db.Model):
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.DateTime, nullable=False, default = datetime.utcnow)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable = False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
category = db.Column(db.String(50), nullable=False)
price = db.Column(db.Integer)
city = db.Column(db.String(), nullable=False)
messages = db.relationship('Message', backref='messages', lazy=True)
def __repr__(self):
return f"Advert('{self.title}', '{self.date}', '{self.category}')"
class Message(db.Model):
id = db.Column(db.Integer, primary_key=True)
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))
title = db.Column(db.String(100), nullable=False)
body = db.Column(db.String(300), nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
ad_title = db.relationship('Advert', foreign_keys='Advert.title', backref='adtitle', lazy='dynamic')
def __repr__(self):
return f"Message('{self.body}')"
but the relationship between Message and Advert tables doesn't work. I want to do that the every Message have refer to Advert title. Anyone know the solution for this problem?
This question already has answers here:
How do I return results from both tables in a SQLAlchemy JOIN?
(1 answer)
How to return all the columns with flask-sqlalchemy query join from two tables
(1 answer)
Closed 3 years ago.
I have two classes in a Flask app joined on Users.taxonomy_id = Taxonomy.id as follows:
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
# Data.
taxonomy_id = db.Column(db.Integer, db.ForeignKey('taxonomy.id',
onupdate='CASCADE', ondelete='CASCADE'),
index=True, nullable=False)
role = db.Column(db.Enum(*ROLE, name='role_types', native_enum=False),
index=True, nullable=False, server_default='member')
active = db.Column('is_active', db.Boolean(), nullable=False,
server_default='1')
username = db.Column(db.String(24), unique=True, index=True)
organisation = db.Column(db.String(255), index=True)
email = db.Column(db.String(255), index=True, nullable=False,
server_default='')
password = db.Column(db.String(128), nullable=False, server_default='')
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
class Taxonomy(db.Model):
__tablename__ = 'taxonomy'
id = db.Column(db.Integer, primary_key=True)
# Relationships.
user = db.relationship(User, uselist=False, backref='taxonomy',
passive_deletes=True)
# Data.
taxonomy = db.Column(db.String(80), index=True, nullable=False)
title = db.Column(db.String(80), index=True, nullable=False)
description = db.Column(db.String(500), index=True, nullable=False,
server_default='')
parent = db.Column(db.Integer, nullable=False, default=0)
member_count = db.Column(db.Integer, nullable=False, default=0)
def __init__(self, **kwargs):
super(Taxonomy, self).__init__(**kwargs)
And both work fine for queries run on them independently such as:
if form.validate_on_submit():
current_user.username = request.form.get('username')
current_user.save()
Or:
t = Taxonomy.query.filter(Taxonomy.id == current_user.taxonomy_id).first()
But I'm having trouble getting them to work as a joined query. I've been playing around for a while with different approaches and can't find anything definitive online that solves my problem. I want to create a joined query based on the classes and return the result. The following works but only returns data from the Users class and table rather than both the users and taxonomy classes:
records = User.query.join(
Taxonomy, User.taxonomy_id == Taxonomy.id).filter(
User.id == 102).first()
Can anybody please help?