简体   繁体   English

在表存在之前,如何使用 flask-sqlalchemy 映射表关系?

[英]How to map table relationships with flask-sqlalchemy, before tables exist?

I have a problem creating relationships between my tables in flask-sqlalchemy.我在 flask-sqlalchemy 中的表之间创建关系时遇到问题。 I have a table with project overview, and from there on out I want to dynamically create new experiment tables with a relationship to my project overview.我有一个带有项目概述的表,从那里开始我想动态创建与我的项目概述相关的新实验表。 However, when I try to define the relationship, sqlalchemy throws the following error:但是,当我尝试定义关系时,sqlalchemy 会引发以下错误:

sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Projects->projects, expression 'Experiment_Overview' failed to locate a name ('Experiment_Overview'). If this is a c
lass name, consider adding this relationship() to the <class 'app.Projects'> class after both dependent classes have been defined.

This seems to be the case because the class Experiment_Overview(db.Model) does not exist yet , which is correct since it will be dynamically generated later on through user input.这似乎是因为 Experiment_Overview(db.Model) 类还不存在,这是正确的,因为稍后将通过用户输入动态生成。 How can I mitigate this error?我怎样才能减轻这个错误?

import os
from flask import Flask, render_template, redirect, request, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
Bootstrap(app)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///DATA/DB.db"
db = SQLAlchemy(app)


def TableCreator(tablename):
  class Experiment_Overview(db.Model):
    __tablename__ = tablename
    creation_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    experiment_name = db.Column(db.String(30), unique=False, nullable=False, primary_key=True)
    projectname = db.Column(db.String(150), db.ForeignKey('projects.projectname'), nullable=False, unique=True)
  return MyTable

class Projects(db.Model):
    projectname = db.Column(db.String(150), unique=True, nullable=False, primary_key=True)
    creation_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    experiments = db.relationship('Experiment_Overview', backref="experiments", lazy=True, uselist=False)

    def __init__(self, owner, projectname, status, created_at):
        self.owner=owner
        self.projectname=projectname
        self.status=status
        self.created_at=created_at

db.create_all()

Generally speaking , you don't dynamically create tables;一般来说,您不会动态创建表; you usually shouldn't create or drop tables while your program is running.您通常不应该在程序运行时创建或删除表。
Additionally, I believe it's impossible to create a true relationship that links back to an entire table.此外,我认为创建链接回整个表格的真实关系是不可能的。 Relationships/Foreign Keys are for linking between rows in tables.关系/外键用于链接表中的行

Don't worry, there are easier ways to achieve the behavior that you are looking for here.别担心,有更简单的方法可以实现您在此处寻找的行为。

From your question it sounds like you can have multiple Projects, and each project can have multiple Experiments within the project.从你的问题听起来你可以有多个项目,每个项目可以在项目中有多个实验。
This would make the relationship between a Project and its Experiments a One-To-Many relationship .这将使项目与其实验之间的关系成为一对多关系

If this is the case, you would need one Projects table (which you have already in your code), and you would also have one Experiments table.如果是这种情况,您将需要一个 Projects 表(您的代码中已经有),并且您还需要一个 Experiments 表。

Each row in the Projects table represents one Project. Projects 表中的每一行代表一个项目。 Each row in the Experiments table represents one Experiment.实验表中的每一行代表一个实验。 The Experiments table will have a column containing a foreign key linking back to the Project the Experiment is linked to. Experiments 表将有一列包含链接回实验所链接到的项目的外键。

I've modified your code according to the One-To-Many example code given in the SQLAlchemy documentation that I linked above.我已经根据上面链接的 SQLAlchemy 文档中给出的一对多示例代码修改了您的代码。 Note the addition of the back_populates option to the relationship() , this allows bi-directional knowledge of the relationship: the Experiment know what project it belongs to, and the Project know what Experiments it has.注意在relationship()中添加了back_populates选项,这允许双向了解关系:实验知道它属于哪个项目,而项目知道它有什么实验。

import os
from flask import Flask, render_template, redirect, request, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
Bootstrap(app)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///DATA/DB.db"
db = SQLAlchemy(app)

class Projects(db.Model):
    __tablename__ = "projects"
    projectname = db.Column(db.String(150), unique=True, nullable=False, primary_key=True)
    creation_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    experiments = db.relationship("Experiment", back_populates="project")

    def __init__(self, owner, projectname, status, created_at):
        self.owner=owner
        self.projectname=projectname
        self.status=status
        self.created_at=created_at

class Experiment(db.Model):
    __tablename__ = "experiments"
    creation_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    experiment_name = db.Column(db.String(30), unique=False, nullable=False, primary_key=True)
    projectname = db.Column(db.String(150), db.ForeignKey('projects.projectname'), nullable=False)
    project = relationship("Project", back_populates="experiments")

db.create_all()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM