pythonclassormsqlalchemy

Automatically Build Database Table based on a Class with SQLAlchemy


I'm really new to SQLAlchemy, and I love it. Right now I'm doing a lot of things manually and I want to do things more 'pythonically' and dynamic.

So as an example, I have this short script that manually creates/defines a table and then a function that inserts data into that table.

database connection

import os
from sqlalchemy import *
from sqlalchemy import schema, types
from sqlalchemy.ext.declarative import declarative_base  

db_url = os.environ.get('DATABASE_URL')
engine = create_engine(db_url)
Base = declarative_base(engine)
meta = Base.metadata

table definition

file_paths = Table('file_paths', meta,
    Column('table_id', Integer, primary_key = True),
    Column('fullpath', String(255)),
    Column('filename', String(255)),
    Column('extension', String(255)),
    Column('created', String(255)),
    Column('modified', String(255)),
    Column('size', Integer),
    Column('owner', String(255)),
    Column('permissions', Integer),
    mysql_engine='InnoDB',
)
file_paths.drop(engine, checkfirst = False)
file_paths.create(engine, checkfirst = True)

insert function takes a string and a list as arguments

def push_to_db(fullpath, fileInfo):
    i = file_paths.insert()
    i.execute(  fullpath    = str(fullpath), 
            filename    = str(fileInfo[0]),
            extension   = str(fileInfo[1]),
            created     = str(fileInfo[2]),
            modified    = str(fileInfo[3]),
            size        = str(fileInfo[4]),
            owner       = str(fileInfo[5]),
            permissions = str(fileInfo[6]),
         )

This works but it's ugly and taken right out of a tutorial I found somewhere online. My goal is to make these operations dynamic.

example class

class FileMeta(object):
    def __init__(self, fullPathFileName, filename):
        self.fullPathFileName = fullPathFileName
        self.filename = filename
        self.extension = os.path.splitext(self.filename)[1].lower()
        ...

    def fileMetaList(self):
        return [self.filename, self.extension, self.created, self.modified,\
                self.size, self.owner, self.permissions]

So here's the scenario: given a class object

  1. define the table dynamically according to the class member variables
    • column numbers and names should correspond to variable names
    • or correspond to the index of that variable in a list of class variables
  2. write a function that can insert data from the class into the corresponding dynamically created table

My intuition tells me this is what SQLAlchemy would be good for. Can someone tell me a good tutorial or reference that can outline this process?


Solution

  • You want to use the declarative extension instead:

    from sqlalchemy.ext.declarative import declarative_base
    
    Base = declarative_base()
    
    class FilePaths(Base):
        __tablename__ = 'file_paths'
        __table_args__ = {'mysql_engine':'InnoDB'}
    
        table_id = Column(Integer, primary_key=True)
        fullpath = Column(String(255))
        filename = Column(String(255))
        extension = Column(String(255))
        created = Column(String(255))
        modified = Column(String(255))
        size = Column(Integer)
        owner = Column(String(255))
        permissions = Column(Integer)
    
    Base.metadata.create_all(engine)
    

    You can define your own __init__() as needed, as well other methods, then create instances of these to insert new rows.

    See the SQLAlchemy's own ORM tutorial.