I am new to sqlalchemy and I have defined a schema using orm for a chat application, but I am having issues with the schema’s relationships, this is what the models are right now, I want some help in how these would be done properly
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship User.rooms – there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a ‘primaryjoin’ expression.
"""
Models
"""
import uuid
from datetime import datetime
from flask_login import UserMixin
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Unicode, Table
from flask import Flask
# from core.config import Config
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///memory"
class Base(DeclarativeBase):
pass
db = SQLAlchemy(app, model_class=Base)
def generate_uuid():
return str(uuid.uuid4())
users_in_room = Table("users_in_room",
Base.metadata,
Column("user_id", String, ForeignKey("user.userID")),
Column("room_id", String, ForeignKey("room.room_id")))
class User(db.Model, UserMixin):
"""
USER MODEL
"""
__tablename__ = "user"
id = db.Column("userID", String, primary_key=True, default=generate_uuid)
username = db.Column("user_name", String, unique=True, nullable=False)
password = db.Column("password", String, nullable=False)
email = db.Column("email", String, nullable=False)
created_rooms = db.relationship("Room", backref="created_by")
rooms = db.relationship("Room", backref="users_in_rooms") # One To Many
messages = db.relationship("Message", backref="sent_by_user")
def set_password(self, secret):
"""
set password method, sets the password by converting it in to a hash
and then stores that hash in the database
"""
# password hash
return generate_password_hash(secret)
def check_password(self, secret):
"""
check password method, checks the password validity by comparing the entered password
during login, with stored hash of the loaded column's password field, the column is
loaded in the login view function, using db.session.scalar(...)
"""
return check_password_hash(self.password, secret)
def __init__(self, username, password, email):
self.username = username
self.password = self.set_password(password)
self.email = email
def __repr__(self):
return f'<User : {self.username}'
class Room(db.Model):
"""
ROOM MODEL
"""
__tablename__ = "room"
room_name = db.Column("room_name", String, nullable=False)
room_id = db.Column("room_id", primary_key=True, default=generate_uuid)
room_banner = db.Column("room_banner", String, nullable=True)
created_by = db.relationship("User", ForeignKey("created_by.id"))
joining_url = db.Column("joining_url", String, nullable=False)
messages: Mapped[list["Message"]] = relationship(backref="sent_to_room")
users = db.relationship("User", backref="users_in_room") # Many To One
def __init__(self, room_name: String, room_banner: String,
joining_url: String, created_by: User):
self.room_name = room_name
self.room_banner = room_banner
self.joining_url = joining_url
self.created_by = created_by
def __repr__(self):
return '<User %r>' % self.joining_url
class Message(db.Model):
"""
MESSAGE MODEL
"""
__tablename__ = "message"
message_id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
user_id: Mapped[str] = mapped_column(ForeignKey("user.id"))
room_id: Mapped[str] = mapped_column(ForeignKey("room.room_id"))
message_body = db.Column("message_body", String)
# message_body can contain image, gif or sound clip, video, stickers -> BLOB (binary large object)
room_id = db.relationship("Room", ForeignKey("users_in_room.id")) # Many To One
sent_by = db.relationship("user", ForeignKey("sent_by_user.id"))
date = db.Column(DateTime(), default=datetime.now)
def __init__(self, message_body: String, sent_by: User, sent_to_room: Room):
self.message_body = message_body
self.sent_to_room = sent_to_room
self.sent_by = sent_by
def __repr__(self):
return '<User %r>' % self.message_body