主要模型的创建/编辑视图中的次要 Table 属性

Secondary Table Attributes in Create / Edit Views for primary models

我希望能够在创建或编辑任一主要 tables。因此,当我编辑其中一个主要 table 并添加与另一个模型的关系时(隐式使用次要 table),我希望能够访问/编辑该次要关系的属性。

更具体地说:

型号

# "Primary" table
class Paper(db.Model):
    __tablename__ = 'papers'
    ...
    chapters = db.relationship(Chapter, secondary="chapter_paper")
    ...

# "Primary" table
class Chapter(db.Model):
    ...
    papers = db.relationship('Paper', secondary="chapter_paper")
    ...

# "Secondary" table
class ChapterPaper(db.Model):
    __tablename__ = 'chapter_paper'
    paper_id = db.Column(db.Integer,
                         db.ForeignKey('papers.id'),
                         primary_key=True)
    chapter_id = db.Column(db.Integer,
                           db.ForeignKey('chapters.id'),
                           primary_key=True)

    ### WANT TO EDIT
    printed = db.Column(db.Boolean, default=False)
    note = db.Column(db.Text, nullable=True)
    ### WANT TO EDIT


    paper = db.relationship('Paper',
                            backref=db.backref("chapter_paper_assoc",
                                               lazy='joined'),
                            lazy='joined')
    chapter = db.relationship(Chapter,
                              backref=db.backref("chapter_paper_assoc",
                                                 lazy='joined'),
                              lazy='joined')

所以,对于这个例子,我希望能够从 flask admin 中 Paper 和 Chapter 的创建/编辑表单编辑 ChapterPaper 的“打印”和“注释”属性。

模型视图

# MainModelView subclasses flask_admin.contrib.sqla.ModelView
class PaperModelView(MainModelView):
    ...
    form_columns = (
        'title',
        'abstract',
        'doi',
        'pubmed_id',
        'link',
        'journals',
        'keywords',
        'authors',
        'chapters',
    )
    # Using form_columns allows CRUD for the many to many
    # relation itself, but does not allow access to secondary attributes
    ...

所以,老实说,我不知道该怎么做。如果我将表单字段添加为附加项,然后手动验证它们......? (我不知道该怎么做)

即便如此,向表单添加额外的字段并不能真正涵盖多个模型。任何人都可以告诉我如何做到这一点,或者给我指点一个教程/甚至是来自某个随机项目一部分的代码的相关示例吗?

谢谢!

好吧,这是很多工作,需要很多 RTFM,但一旦开始,它就非常简单了。

没有整洁的方法 API 是扩展模型视图并用您自己的表单替换创建/编辑表单。

这是我的表格class:

class ExtendedPaperForm(FlaskForm):
    title = StringField()
    abstract = TextAreaField()
    doi = StringField()
    pubmed_id = StringField()
    link = StringField()
    journals = QuerySelectMultipleField(
        query_factory=_get_model(Journal),
        allow_blank=False,
    )
    issue = StringField()
    volume = StringField()
    pages = StringField()
    authors = QuerySelectMultipleField(
        query_factory=_get_model(Author),
        allow_blank=False,
    )
    keywords = QuerySelectMultipleField(
        query_factory=_get_model(Keyword),
        allow_blank=True,
    )
    chapters_printed = QuerySelectMultipleField(
        query_factory=_get_model(Chapter),
        allow_blank=True,
        label="Chapters (Printed)",
    )
    chapters = QuerySelectMultipleField(
        query_factory=_get_model(Chapter),
        allow_blank=True,
        label="Chapters (All)",
    )

实现此功能的重要部分是 on_model_change 方法,该方法在保存模型之前执行操作。

...
    def on_model_change(self, form, model, is_created):
        """
        Perform some actions before a model is created or updated.
        Called from create_model and update_model in the same transaction (if it has any meaning for a store backend).
        By default does nothing.

        Parameters:
        form – Form used to create/update model
        model – Model that will be created/updated
        is_created – Will be set to True if model was created and to False if edited
        """

        all_chapters = list(set(form.chapters.data + form.chapters_printed.data))
        for chapter in all_chapters:

            if chapter in form.chapters_printed.data:  # if chapter in both, printed takes priority
                chapter_paper = ChapterPaper.query.filter_by(chapter_id=chapter.id, paper_id=model.id).first()

                if not chapter_paper:
                    chapter_paper = ChapterPaper(chapter_id=chapter.id, paper_id=model.id)

                chapter_paper.printed = True
                db.session.add(chapter_paper)

        journal = None
        if form.journals.data:
            journal = form.journals.data[0]

        if journal:  # Assumes only 1 journal if there are any journals in this field
            issue = form.issue.data
            volume = form.volume.data
            pages = form.pages.data
            journal_paper = JournalPaper.query.filter_by(journal_id=journal.id, paper_id=model.id).first()

            if not journal_paper:
                journal_paper = JournalPaper(journal_id=journal.id, paper_id=model.id)

            journal_paper.issue = issue
            journal_paper.volume = volume
            journal_paper.pages = pages
            db.session.add(journal_paper)
...