so I got two files: auth.py and chats.py
The main goal: The two classes in two different files must be bound to each other using foreign key
The main problem: But to do this, foreign key requires me to import files. If I do so, I get into circular import, if I don't, then both classes dont recognize each other.
When I try to bind two classes with foreign key, I got stuck in circular import, since I am importing my classes in both files.
# auth.py:
from sqlalchemy import (
create_engine,
Column,
Integer,
BigInteger,
String,
Text,
Boolean,
DateTime,
ForeignKey,
Enum,
Table,
UniqueConstraint,
)
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.dialects.postgresql import UUID
import uuid
from src.settings import settings
from sqlalchemy.sql import func
from .legacy.base_model import BaseModel
from .chats import Admin, Group
class User(BaseModel):
__tablename__ = "user"
username = Column(String)
first_name = Column(String)
last_name = Column(String)
bio = Column(Text)
avatar = Column(String)
gender = Column(Boolean)
birthdate = Column(DateTime)
email = Column(String, unique=True)
password = Column(String)
phone_number = Column(String)
live_status = Column(Boolean)
last_seen = Column(DateTime)
language = Column(UUID(as_uuid=True), ForeignKey("locale.id"))
admins = relationship("Admin", back_populates="user")
groups = relationship("Group", back_populates="owner")
class Locale(BaseModel):
__tablename__ = "locale"
code = Column(String)
# chats.py
from sqlalchemy import (
create_engine,
Column,
Integer,
BigInteger,
String,
Text,
Boolean,
DateTime,
ForeignKey,
Enum,
Table,
UniqueConstraint,
)
from sqlalchemy.orm import relationship, sessionmaker, declared_attr
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql import func
import uuid
from .legacy.base_model import BaseModel
from src.settings import settings
from .auth import User # here is the main problem, I am importing User here, and
# in auth.py file the Admin class below also was imported
class Admin(BaseModel):
__tablename__ = "admins"
chat_id = Column(UUID(as_uuid=True), ForeignKey("channel.id"))
chat_type = Column(Enum("channel", "group", "direct", name="chat_type_enum"))
user_id = Column(UUID(as_uuid=True), ForeignKey("user.id"))
admin_name = Column(String)
channel = relationship("Channel", back_populates="admins")
class Group(BaseModel):
__tablename__ = "group"
owner_id = Column(UUID(as_uuid=True), ForeignKey("user.id"))
title = Column(String)
code = Column(String)
member_count = Column(BigInteger)
description = Column(Text)
avatar = Column(String)
visibility = Column(Boolean)
owner = relationship("User", back_populates="groups")
class Subscriber(BaseModel):
__tablename__ = "subscribers"
chat_id = Column(UUID(as_uuid=True), ForeignKey("channel.id"))
user_id = Column(UUID(as_uuid=True), ForeignKey("user.id"))
channel = relationship("Channel", back_populates="subscribers")
class Channel(BaseModel):
__tablename__ = "channel"
title = Column(String)
description = Column(Text)
code = Column(String)
avatar = Column(String)
member_count = Column(BigInteger)
owner_id = Column(UUID(as_uuid=True), ForeignKey("user.id"))
admins = relationship("Admin", back_populates="channel")
subscribers = relationship("Subscriber", back_populates="channel")
and I also have BaseModel class which was bound to declarative base and gives some basic default columns for all of my tables:
from sqlalchemy import String, UUID, Column, DateTime, Boolean
from sqlalchemy.orm import mapped_column, Mapped
from sqlalchemy.sql import func
import uuid
from src.db.orm.config import SessionLocal
from src.db.orm.config import Base
from src.logger import logger
class BaseModel(Base):
"""
This class serves as a base model for all other database models in the application.
It provides common fields such as id, created_at, updated_at, and status.
Attributes:
- id (UUID): Unique identifier for each record.
- created_at (DateTime): Timestamp indicating when the record was created.
- updated_at (DateTime): Timestamp indicating when the record was last updated.
"""
__abstract__ = True
id = Column(UUID, default=uuid.uuid4, primary_key=True, nullable=False)
created_at = Column(DateTime, nullable=True, default=func.now())
updated_at = Column(
DateTime, nullable=True, default=func.now(), onupdate=func.now()
)
def __repr__(self):
raise NotImplementedError("Please implement the description of the table")
def save(self):
"""Save the instance to the database."""
try:
session = SessionLocal()
session.add(self)
sessionmit()
logger.info("Saved successfully")
return self
except Exception as e:
session.rollback()
raise e
But if I dont import them, they wont recognize each other. I am really wondering that do I have a chance to just assign it like I assign in django, like this: src.db.orm.auth.User inside the Admin class and vice versa.
Any advice or help is strongly appreciated.
I tried to import both files to each other, but got into circular import.