2016-12-12 5 views
0

У меня есть довольно простая фляга, подключенная к базе данных postgresql. В основном я использую флеш-приложение с flask-admin, так что я могу добавлять записи в базу данных и, возможно, позже выстраивать их в панель инструментов. В основном это каталог внутреннего использования.сеанс sqlalchemy для создания или обновления записей с * многими отношениями

То, что я пытаюсь сделать, также написать скрипт, который подключается к стороннему API для добавления/обновления записей в базе данных, поэтому он не попадает в приложение для флэшей. Я использую SQLAlchemy для этого, потому что он совместим с приложением, и мне просто нужно что-то работать без суеты над операторами SQL.

модель данных Колбы приложения в определяются как например:

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 с некоторыми основными метаданными и у них есть один ко многим отношений с FilePath к документ и отношение многих ко многим к числу ключевых слов.

Отдельный скрипт подключается непосредственно к базе данных и сопоставляет существующие таблицы с объектами, которые я могу использовать для создания сеанса и изменения базы данных.

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, но при просмотре документации и некоторых учебных пособий я не вижу недостающих частей загрузки этих отношений в сеанс, чтобы я мог глотать все данные в базы данных.

ответ

0

Обновите свои определения моделей, чтобы добавить функции конструктора. В этом случае он позволяет передавать параметры объекту при создании экземпляра.

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() 

Я проверил код на местном уровне и надеемся, что он работает для вас.

Смежные вопросы