![](/img/trans.png)
[英]Update many-to-many relationships using Flask, SQLAlchemy and WTForms?
[英]sqlalchemy session to create or update records with * to many relationships
我有一个连接到PostgreSQL数据库的相当简单的flask应用程序。 我主要是将flask应用程序与flask-admin一起使用,以便可以将记录添加到数据库中,并稍后再将其构建到仪表板中。 基本上,这是一个内部使用目录。
我正在尝试做的是还要编写一个脚本,该脚本连接到第三方API以添加/更新数据库中的记录,因此它不会通过flask应用程序获取。 我正在使用SQLAlchemy来执行此操作,因为它与应用程序一致,我只需要一些工作即可,而不必大惊小怪。
flask应用程序的数据模型定义如下:
app.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.dialects import postgresql
from flask_admin import Admin
# ... APPLICATION CONFIGURATION ...
# db Models
## Table for many to many
keywords = db.Table('keywords',
db.Column('keyword_id', db.Integer, db.ForeignKey('keyword.id')),
db.Column('dataset_id', db.String(24), db.ForeignKey('dataset.dataset_id')),
)
## Model classes
class Dataset(db.Model):
title = db.Column(db.String(120))
description = db.Column(db.Text())
dataset_id = db.Column(db.String(24), primary_key=True, unique=True)
#relationships
dataset_documentation = db.relationship('DataDocument', backref='dataset', lazy='dynamic')
keywords = db.relationship('Keyword', secondary=keywords, backref='dataset', lazy='dynamic')
def __str__(self):
return self.title
class Keyword(db.Model):
id = db.Column(db.Integer, primary_key=True)
keyword = db.Column(db.String(80))
def __str__(self):
return self.keyword
class DataDocument(db.Model):
id = db.Column(db.Integer, primary_key=True)
document = db.Column(db.String(120))
dataset_id = db.Column(db.String(24), db.ForeignKey('dataset.dataset_id'))
def __str__(self):
return self.document
# ... APPLICATION VIEWS ...
因此,我们具有一些基本元datasets
,它们与文档的文件路径具有一对多的关系,与任意数量的关键字具有多对多的关系。
单独的脚本直接连接到数据库,并将现有的表映射到对象,我可以使用这些对象来创建会话和修改数据库。
script.py
import config #local config only
from sqlalchemy import create_engine, MetaData, Table
from sqlalchemy.orm import mapper, sessionmaker
# Connecting to postgres database and creating a session with database objects, intantiate empty classes to populate
class Dataset(object):
pass
class DataDocument(object):
pass
class Keyword(object):
pass
## How to instantiate the MTM association table?
db_uri = config.SQLALCHEMY_DATABASE_URI
engine = create_engine(db_uri)
meta = MetaData(engine)
dataset_table = Table('dataset', meta, autoload=True) #correct
datadocument_table = Table('dataset', meta, autoload=True) #incorrect?
keyword_table = Table('keyword', meta, autoload=True) #incorrect?
mapper(Dataset, dataset_table) #correct
mapper(DataDocument, datadocument_table, meta, autoload=True) #??
mapper(Keyword, keyword_table, meta, autoload=True) #??
Session = sessionmaker(bind=engine)
session = Session()
# sample update
data_upsert = Dataset()
data_upsert.title = "Some title"
data_upsert.dataset_id = "Uniq_ID-123"
data_upsert.description = "lorem ipsum foo bar foo"
session.merge(data_upsert)
#attempt to add related properties
key1 = Keyword('test1')
key2 = Keyword('test2')
datadoc = DataDocument('path/to/document.txt')
# FAIL.
data_upsert.append(key1)
data_upsert.append(key2)
data_upsert.append(datadoc)
session.flush()
我是sqlalchemy的新手,我几乎不能全力以赴地在数据库引擎的脚本中创建Dataset
对象。 但是我也在考虑加载Keyword
和Datadocument
表时,它已经基于从数据库中加载的内容理解了它们之间的关系,但这正是我的理解薄弱的地方。
有没有简单的方法可以在此处完成图片? 我假设在script.py
再次明确定义我的模型没有意义,但是在查看文档和一些教程时,我没有看到将这些关系加载到会话中的缺失部分,因此我可以提取所有数据导入数据库。
更新模型定义以添加构造函数。 在这种情况下,它允许您在实例化时将参数传递给对象。
models.py
## Model classes
class Dataset(db.Model):
title = db.Column(db.String(120))
description = db.Column(db.Text())
dataset_id = db.Column(db.String(24), primary_key=True, unique=True)
#relationships
dataset_documentation = db.relationship('DataDocument', backref='dataset', lazy='dynamic')
keywords = db.relationship('Keyword', secondary=keywords, backref='dataset', lazy='dynamic')
def __init__(self, title=None, desc=None, dataset_id=None):
self.title = title
self.description = desc
self.dataset_id = dataset_id
def __str__(self):
return self.title
class Keyword(db.Model):
id = db.Column(db.Integer, primary_key=True)
keyword = db.Column(db.String(80))
def __init__(self, keyword=None):
self.keyword = keyword
def __str__(self):
return self.keyword
class DataDocument(db.Model):
id = db.Column(db.Integer, primary_key=True)
document = db.Column(db.String(120))
dataset_id = db.Column(db.String(24), db.ForeignKey('dataset.dataset_id'))
def __init__(self, document, dataset_id):
self.document = document
self.dataset_id = dataset_id
def __str__(self):
return self.document
无需在script.py中再次定义模型类。 您可以简单地从models.py中导入要使用的类。 然后,您可以通过以下方式将数据对象及其相关对象一起插入数据库:
script.py
import config #local config only
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from models import Dataset, DataDocument, Keyword
def loadSession(engine):
""""""
Session = sessionmaker(bind=engine)
session = Session()
return session
engine = create_engine(config.SQLALCHEMY_DATABASE_URI, echo=False)
Base = declarative_base(engine)
# load session
session = loadSession(engine)
data_upsert = Dataset(title="Some title", dataset_id="Uniq_ID-125", desc="lorem ipsum foo bar foo")
# add related properties here
key1 = Keyword('test1')
key2 = Keyword('test2')
datadoc = DataDocument('path/to/document.txt', dataset_id="Uniq_ID-125")
# append the properties to the object
data_upsert.dataset_documentation.append(datadoc)
data_upsert.keywords.append(key1)
data_upsert.keywords.append(key2)
session.add(data_upsert)
session.commit()
我已经在本地测试了该代码,希望它对您有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.