SQLAlchemy и Flask-Admin: теги для записей со связь Many to Many
Для нашего блога решил добавить теги, чтобы похожие записи было проще искать и вообще это модно сейчас. Ранее использовал обычный массив с ForeignKey, и это работает, но... Всегда есть но, в Flask-Admin для того чтобы появился мультиселект с вариантами из другой таблички этого уже недостаточно.
И так начнем с проблемы:
Есть много тегов и также немало статей, их нужно связать методом "многий ко многим", а для удобства редактирование в админ панели, в форме редактирования статьи, должен появится мультиселект с этими самыми тегами.
Начнем с модельки самого тега, тут есть одна особенность:
class TagModel(db.Model): __tablename__ = 'tag' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String) weight = db.Column(db.Integer, index=True, default=0) create_date = db.Column(db.DateTime, default=datetime.datetime.now) def __str__(self): return self.name
Для того что-бы Flask-Admin в селекте выводил нормально название добавляем функцию __str__, она то как раз и будет отвечать за формирование имени в селекте.
Далее модель статьи:
class ArticleModel(db.Model): __tablename__ = 'article' _cover = None id = db.Column(db.Integer, primary_key=True) chpu = db.Column(db.String) title = db.Column(db.String) keywords = db.Column(db.String) description = db.Column(db.String) state = db.Column(db.Integer, index=True, default=ARTICLE_EDIT) tags = db.relationship(TagModel, secondary=article_tags_meta) cover_id = db.Column(db.Integer) name = db.Column(db.String) preview = db.Column(db.String) body = db.Column(db.TEXT) update_date = db.Column(db.DateTime, default=datetime.datetime.now) create_date = db.Column(db.DateTime, default=datetime.datetime.now)
Здесь мы добавиляем отношение:
tags = db.relationship(TagModel, secondary=article_tags_meta)
article_tags_meta это промежуточная таблица со связями, выглядет она следующим образом:
article_tags_meta = db.Table( 'article_tags', db.Model.metadata, db.Column('article_id', db.Integer, db.ForeignKey('article.id')), db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')), extend_existing=True )
И по результату, без лишней магии и телодвижений получаем в админ панели: