Я участвую в проекте небольшого местного сообщества и одновременно изучаю Python. Я впервые использую Flask и SQLAlchemy (для хранения данных используется MySQL). Выбранный мною ORM поначалу работал нормально, но когда я попытался переключиться на модель «многие-ко-многим» между двумя таблицами, следуя этому официальному руководству, эта ошибка «NoReferencedTableError» начала появляться во время инициализации основного приложения Flask.
Вот полная ошибка:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'assoc_tbl_1_user_X_challenge.challengeId' could not find table 'challengesTbl' with which to generate a foreign key to target column 'id'
...
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'Mapper[User(usersTbl)]'. Original exception was: Foreign key associated with column 'assoc_tbl_1_user_X_challenge.challengeId' could not find table 'challengesTbl' with which to generate a foreign key to target column 'id'
Как бы я ни старался, я не могу найти ошибку в своих определениях. Я пытался найти эту ошибку в Google, но в других случаях, похоже, люди делают опечатки в именах таблиц или классов - я дважды проверил, опечаток здесь нет. Я начинаю подозревать, что это может быть как-то связано с тем фактом, что переменная Association_table1 определяется до классов, определяющих другие таблицы, и когда она создается, она не может их найти. Но даже если я перенесу его в конец файла, он все равно не будет работать, поскольку на него ссылаются определения других классов таблиц. Предварительное объявление его и инициализация в конце файла тоже не помогли.
Я также заметил, что когда я пытаюсь запустить внешний скрипт, который предварительно инициализирует мою базу данных, используя тот же ORM файле, похоже, созданы только три таблицы:
mysql> show tables;
+------------------------------+
| Tables_in_nekoko$ABsitedb |
+------------------------------+
| challengesTbl |
| rideRecordingsTbl |
| usersTbl |
+------------------------------+
3 rows in set (0.00 sec)
Я не вижу таблицы ассоциаций assoc_tbl_1_user_X_challenge, разве ее не следует создать одновременно?
Мой текущий модель данных такая:
from . import db
from flask_login import UserMixin
from sqlalchemy import text
class Base(db.DeclarativeBase):
pass
association_table1 = db.Table(
"assoc_tbl_1_user_X_challenge",
Base.metadata,
db.Column("userId", db.ForeignKey("usersTbl.id"), primary_key=True),
db.Column("challengeId", db.ForeignKey("challengesTbl.id"), primary_key=True),
)
class User(UserMixin, db.Model):
__tablename__ = "usersTbl"
id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(1000))
givenName = db.Column(db.String(100))
sn = db.Column(db.String(100))
totalDistanceKm = db.Column(db.Float, server_default=text("0.0"))
groups = db.Column(db.JSON, nullable=False)
isActive = db.Column(db.Boolean, default=True, nullable=False, index=True)
challenges = db.relationship('Challenge', secondary=association_table1, back_populates="participants")
rides = db.relationship('Ride', backref='usersTbl', lazy=True)
def __repr__(self):
return f''
class Ride(db.Model):
__tablename__ = "rideRecordingsTbl"
id = db.Column(db.Integer, primary_key=True)
rideRecording = db.Column(db.LargeBinary)
#rideRecording = db.Column(db.LONGBLOB, nullable=False)
rideName = db.Column(db.String(150))
distanceKm = db.Column(db.Float, server_default=text("0.0"))
duration = db.Column(db.Time)
uploadDateTime = db.Column(db.DateTime)
stream_hash = db.Column(db.String(1000))
ownerId = db.Column(db.Integer, db.ForeignKey('usersTbl.id'), nullable=False)
def __repr__(self):
return f''
class Challenge(db.Model):
__tablename__ = "challengesTbl"
id = db.Column(db.Integer, primary_key=True)
rideRecording = db.Column(db.LargeBinary)
challengeName = db.Column(db.String(150))
challengeTargetDistanceKm = db.Column(db.Float, server_default=text("0.0"))
challengeCurrnetTotalDistanceKm = db.Column(db.Float, server_default=text("0.0"))
challengeEnds = db.Column(db.DateTime)
challengeStarts = db.Column(db.DateTime)
createdByUserId = db.Column(db.Integer)
isActive = db.Column(db.Boolean, default=True, nullable=False, index=True)
participants = db.relationship('User', secondary=association_table1, back_populates="challenges")
def __repr__(self):
return f''
Решено! Вот подробности:
Во-первых, @dann были правы относительно проблем с частями, которые использовались до того, как было объявлено, их предложение было в правильном направлении. После этого это все еще не работало, пока я не применил решение, предложенное @matthew-moisen в этой теме.
Я все же решил отметить ответ @dann как решение, как Я думаю, что это сделало большую часть работы. Спасибо!
Итак, наконец, соответствующая часть стала выглядеть так (полный контекст см. в ответе Данна ниже):
association_table1 = db.Table(
"assoc_tbl_1_user_X_challenge",
Base.metadata,
#db.Column("userId", db.ForeignKey("usersTbl.id"), primary_key=True),
#db.Column("challengeId", db.ForeignKey("challengesTbl.id"), primary_key=True)
db.Column("userId", db.ForeignKey(User.id), primary_key=True),
db.Column("challengeId", db.ForeignKey(Challenge.id), primary_key=True)
)
User.challenges = db.relationship('Challenge', secondary=association_table1, back_populates="participants")
Challenge.participants = db.relationship('User', secondary=association_table1, back_populates="challenges")
Подробнее здесь: https://stackoverflow.com/questions/787 ... ny-to-many