การใช้ Flask-SQLAlchemy โดยไม่มี Flask

ฉันมีบริการเว็บขนาดเล็กที่สร้างขึ้นโดยใช้ Flask และ Flask-SQLAlchemy ซึ่งมีเพียงรุ่นเดียวเท่านั้น ตอนนี้ฉันต้องการใช้ฐานข้อมูลเดียวกัน แต่ด้วยแอปบรรทัดคำสั่ง ดังนั้นฉันจึงต้องการยกเลิกการพึ่งพา Flask

โมเดลของฉันมีลักษณะดังนี้:

class IPEntry(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    ip_address = db.Column(db.String(16), unique=True)
    first_seen = db.Column(db.DateTime(),
        default = datetime.datetime.utcnow
    )
    last_seen = db.Column(db.DateTime(),
        default = datetime.datetime.utcnow
    )

    @validates('ip')
    def validate_ip(self, key, ip):
        assert is_ip_addr(ip)
        return ip

เนื่องจาก db จะไม่อ้างอิงถึง flask.ext.sqlalchemy.SQLAlchemy(app) อีกต่อไป ฉันจะแปลงโมเดลของฉันให้ใช้เพียง SQLAlchemy ได้อย่างไร มีวิธีสำหรับทั้งสองแอปพลิเคชัน (อันหนึ่งที่มี Flask-SQLAlchemy อีกอันที่มี SQLAlchemy) เพื่อใช้ฐานข้อมูลเดียวกันหรือไม่


person amccormack    schedule 08.05.2015    source แหล่งที่มา
comment
ฐานข้อมูล ควรเป็นอิสระจาก รุ่น หรือเลเยอร์ ORM ที่คุณใช้   -  person Makoto    schedule 08.05.2015
comment
ใช่ฉันเข้าใจแล้ว ฉันกำลังมองหาวิธีนำโค้ดกลับมาใช้ซ้ำทั้งในขวดและไม่ใช่ขวดโดยไม่ต้องเปลี่ยนคำจำกัดความของโมเดลด้วยวิธีที่สำคัญใดๆ   -  person amccormack    schedule 08.05.2015
comment
ไม่มีสิ่งใดที่เกี่ยวข้องกับขวดในแบบจำลองของคุณ สิ่งที่คุณต้องทำคือสร้างการเชื่อมต่อ db และนำเข้าโมเดลของคุณไปยังแอป flask หรือที่ไม่ใช่ flask ฉันเพียงแค่ใส่โมเดลใน 'models.py' ดังนั้น (จริงๆ เพียงแค่ย้ายด้านบนจากไฟล์ .py หลักขวด และนำเข้า/สร้างอินสแตนซ์ IPentry เมื่อจำเป็น)   -  person GG_Python    schedule 09.05.2015


คำตอบ (7)


คุณสามารถทำเช่นนี้เพื่อแทนที่ db.Model:

from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base
import sqlalchemy as sa

base = declarative_base()
engine = sa.create_engine(YOUR_DB_URI)
base.metadata.bind = engine
session = orm.scoped_session(orm.sessionmaker())(bind=engine)

# after this:
# base == db.Model
# session == db.session
# other db.* values are in sa.*
# ie: old: db.Column(db.Integer,db.ForeignKey('s.id'))
#     new: sa.Column(sa.Integer,sa.ForeignKey('s.id'))
# except relationship, and backref, those are in orm
# ie: orm.relationship, orm.backref
# so to define a simple model

class UserModel(base):
    __tablename__ = 'users' #<- must declare name for db table
    id = sa.Column(sa.Integer,primary_key=True)
    name = sa.Column(sa.String(255),nullable=False)

จากนั้นให้สร้างตาราง:

 base.metadata.create_all()
person Kyle Roux    schedule 16.05.2017

ตรวจสอบอันนี้ github.com/mardix/active-alchemy

Active-Alchemy เป็น Wrapper ที่ไม่เชื่อเรื่องเฟรมเวิร์กสำหรับ SQLAlchemy ที่ทำให้ใช้งานง่ายมากโดยการนำบันทึกที่ใช้งานอยู่อย่าง api มาใช้ ในขณะที่ยังคงใช้ db.session อยู่ข้างใต้ แรงบันดาลใจจาก Flask-SQLAlchemy

person Levon    schedule 16.07.2016

นั่นคือวิธีการใช้ SQLAlchemy โดยไม่ต้องใช้ Flask (เช่น การเขียนออบเจ็กต์จำนวนมากไปยังฐานข้อมูล PostgreSQL):

from sqlalchemy import Column, Integer, String
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# Define variables DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, DB_NAME   
SQLALCHEMY_DATABASE_URI = f'postgresql://{DB_USERNAME}:{DB_PASSWORD}@{DB_HOST}: 
{DB_PORT}/{DB_NAME}'

# ----- This is related code -----
engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=True)
Base = declarative_base()
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
Session.configure(bind=engine)
session = Session()
# ----- This is related code -----

class MyModel(Base):
    __tablename__ = 'my_table_name'

    id = Column(Integer, primary_key=True)
    value = Column(String)

objects = [MyModel(id=0, value='a'), MyModel(id=1, value='b')]
session.bulk_save_objects(objects)
session.commit()
person Galina Alperovich    schedule 08.03.2019
comment
ฉันไม่คิดว่าคำถามนี้เกี่ยวข้องกับการแทรกจำนวนมาก - person Kyle Roux; 02.05.2019
comment
การแทรกจำนวนมาก @KyleRoux เป็นเพียงตัวอย่างง่ายๆ ในการสร้างโค้ดที่ทำซ้ำได้ ส่วนที่เกี่ยวข้องคือเส้น 6 เส้นด้านบนที่ฉันสร้างเครื่องยนต์ ฉันใช้เวลาค่อนข้างมากในการทำให้มันทำงานโดยไม่ใช้ Flask ด้วยวิธีนี้ ดังนั้นไม่แน่ใจว่าทำไมคุณถึงคิดว่ามันไม่เกี่ยวข้อง :/ - person Galina Alperovich; 06.05.2019
comment
พบว่าสิ่งนี้ค่อนข้างมีประโยชน์และกะทัดรัด - person Francois; 03.12.2019

มีบทความดีๆ เกี่ยวกับ Flask-SQLAlchemy: วิธีการทำงาน และวิธีแก้ไขโมเดลเพื่อใช้นอก Flask:

http://derrickgilland.com/posts/demystifying-flask-sqlalchemy/

person maxkoryukov    schedule 25.10.2017
comment
นี่เป็นลิงก์ที่ดี แต่ขณะนี้ใช้งานไม่ได้หรือใช้งานไม่ได้ https://web.archive.org/web/20190530064812/http://derrickgilland.com/posts/demystifying-flask-sqlalchemy/ ช่วยได้ - person Yehosef; 01.01.2020

เอกสาร sqlalchemy มีบทช่วยสอน ที่ดีพร้อมตัวอย่างที่ฟังดูเหมือนสิ่งที่คุณ อยากทำ.

แสดงวิธีเชื่อมต่อกับฐานข้อมูล การแมป การสร้างสคีมา และการสืบค้น/การบันทึกไปยังฐานข้อมูล

person juzten    schedule 08.05.2015
comment
ควรอัปเดตลิงก์... docs.sqlalchemy.org/en/latest/ orm/tutorial.html - person Inego; 15.10.2018

สิ่งนี้ไม่ได้ตอบคำถามของคุณอย่างสมบูรณ์ เนื่องจากไม่ได้ลบการพึ่งพา Flask แต่คุณสามารถใช้ SqlAlchemy ในสคริปต์และการทดสอบได้เพียงแค่ ไม่ได้ทำงาน แอป Flask

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData

test_app = Flask('test_app')
test_app.config['SQLALCHEMY_DATABASE_URI'] = 'database_uri'
test_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

metadata = MetaData(schema='myschema')
db = SQLAlchemy(test_app, metadata=metadata)

class IPEntry(db.Model):
    pass

ปัญหาประการหนึ่งที่คุณอาจพบคือข้อกำหนดในการใช้ db.Model เป็นคลาสพื้นฐานสำหรับโมเดลของคุณ หากคุณต้องการกำหนดเป้าหมายเว็บแอปและสคริปต์อิสระโดยใช้โค้ดเบสเดียวกัน วิธีที่เป็นไปได้ในการจัดการกับมันคือการใช้ dynamic polymorphism และรวมคำจำกัดความของคลาสไว้ในฟังก์ชัน

def get_ipentry(db):
    class IPEntry(db.Model):
        pass
    return IPEntry

เมื่อคุณสร้างคลาสรันไทม์ในฟังก์ชัน คุณสามารถส่งผ่านอินสแตนซ์ SqlAlchemy ที่แตกต่างกันได้ ข้อเสียเพียงอย่างเดียวคือคุณต้องเรียกใช้ฟังก์ชันเพื่อสร้างคลาสก่อนใช้งาน

db = SqlAlchemy(...)
IpEntry = get_ipentry(db)
IpEntry.query.filter_by(id=123).one()
person Timo    schedule 26.07.2017

Flask (> 1.0) พยายามจัดหาผู้ช่วยเหลือในการแชร์โค้ดระหว่างเว็บแอปพลิเคชันและอินเทอร์เฟซบรรทัดคำสั่ง โดยส่วนตัวแล้วฉันคิดว่ามันอาจจะสะอาดกว่า เบากว่า และง่ายกว่าในการสร้างไลบรารี่ที่ไม่ผูกติดกับขวด แต่คุณอาจต้องการตรวจสอบ:

person bufh    schedule 03.06.2015
comment
ขณะนี้ลิงก์ทั้งสองนี้ดูเหมือนว่าจะใช้งานไม่ได้ - person holdenweb; 21.11.2018
comment
@holdenweb ‹ ลิงก์ไปยังเอกสารอย่างเป็นทางการได้รับการแก้ไขแล้ว ขอบคุณสำหรับการรายงาน - person bufh; 30.11.2018