def codegen(args): # Use reflection to fill in the metadata engine = create_engine(args.url) metadata = MetaData(engine) tables = args.tables.split(",") if args.tables else None metadata.reflect(engine, args.schema, not args.noviews, tables) if db.session.bind.dialect.name == "sqlite": # dirty hack for sqlite engine.execute("""PRAGMA journal_mode = OFF""") # Write the generated model code to the specified file or standard output capture = StringIO() # outfile = io.open(args.outfile, 'w', encoding='utf-8') if args.outfile else capture # sys.stdout generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses) generator.render(capture) generated = capture.getvalue() generated = fix_generated(generated) if args.outfile: outfile = io.open(args.outfile, "w", encoding="utf-8") outfile.write(generated) return generated
def main(): parser = argparse.ArgumentParser(description='Generates SQLAlchemy model code from an existing database.') parser.add_argument('url', nargs='?', help='SQLAlchemy url to the database') parser.add_argument('--version', action='store_true', help="print the version number and exit") parser.add_argument('--schema', help='load tables from an alternate schema') parser.add_argument('--tables', help='tables to process (comma-separated, default: all)') parser.add_argument('--noviews', action='store_true', help="ignore views") parser.add_argument('--noindexes', action='store_true', help='ignore indexes') parser.add_argument('--noconstraints', action='store_true', help='ignore constraints') parser.add_argument('--nojoined', action='store_true', help="don't autodetect joined table inheritance") parser.add_argument('--noinflect', action='store_true', help="don't try to convert tables names to singular form") parser.add_argument('--noclasses', action='store_true', help="don't generate classes, only tables") parser.add_argument('--alwaysclasses', action='store_true', help="always generate classes") parser.add_argument('--nosequences', action='store_true', help="don't auto-generate postgresql sequences") parser.add_argument('--outfile', help='file to write output to (default: stdout)') args = parser.parse_args() if args.version: print(sqlacodegen.version) return if not args.url: print('You must supply a url\n', file=sys.stderr) parser.print_help() return engine = create_engine(args.url) metadata = MetaData(engine) tables = args.tables.split(',') if args.tables else None metadata.reflect(engine, args.schema, not args.noviews, tables) outfile = codecs.open(args.outfile, 'w', encoding='utf-8') if args.outfile else sys.stdout generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses, args.alwaysclasses, args.nosequences) generator.render(outfile)
def main(): parser = argparse.ArgumentParser( description='Generates SQLAlchemy model code from an existing database.' ) parser.add_argument('url', nargs='?', help='SQLAlchemy url to the database') parser.add_argument('--version', action='store_true', help="print the version number and exit") parser.add_argument('--schema', help='load tables from an alternate schema') parser.add_argument( '--tables', help='tables to process (comma-separated, default: all)') parser.add_argument('--noviews', action='store_true', help="ignore views") parser.add_argument('--noindexes', action='store_true', help='ignore indexes') parser.add_argument('--noconstraints', action='store_true', help='ignore constraints') parser.add_argument('--nojoined', action='store_true', help="don't autodetect joined table inheritance") parser.add_argument( '--noinflect', action='store_true', help="don't try to convert tables names to singular form") parser.add_argument('--noclasses', action='store_true', help="don't generate classes, only tables") parser.add_argument('--column_lower', action='store_true', help="generate column lower classes") parser.add_argument('--outfile', help='file to write output to (default: stdout)') args = parser.parse_args() if args.version: version = pkg_resources.get_distribution('sqlacodegen').parsed_version print(version.public) return if not args.url: print('You must supply a url\n', file=sys.stderr) parser.print_help() return engine = create_engine(args.url) metadata = MetaData(engine) tables = args.tables.split(',') if args.tables else None metadata.reflect(engine, args.schema, not args.noviews, tables) outfile = codecs.open(args.outfile, 'w', encoding='utf-8') if args.outfile else sys.stdout generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses, args.column_lower) generator.render(outfile)
def _gen_models(metadata) -> None: """使用sqlacodegen生成sqlalchemy模型 """ from sqlacodegen.codegen import CodeGenerator generator = CodeGenerator(metadata) f = open("sqlalchemy_models.py", "w", encoding="utf-8") generator.render(f) f.close()
def generate_code(engine, **kwargs): """ CodeGenerator.__init__(self, metadata, noindexes=False, noconstraints=False, nojoined=False, noinflect=False, nobackrefs=False, flask=False, ignore_cols=None, noclasses=False, nocomments=False) """ metadata = MetaData() metadata.reflect(bind=engine) codegen = CodeGenerator(metadata, **kwargs) sio = StringIO() codegen.render(sio) return sio.getvalue()
def test_table_comment(metadata): Table('simple', metadata, Column('id', INTEGER, primary_key=True), comment="this is a 'comment'") codegen = CodeGenerator(metadata, noclasses=True) code = codegen.render_table(codegen.models[0]) assert code == """\ t_simple = Table( 'simple', metadata, Column('id', Integer, primary_key=True), comment='this is a \\'comment\\'' ) """ code = generate_code(metadata) assert code == """\
def sql_backend_file_to_table_upload(upload_form, csvfiles): """ :param upload_form: flask request form :param csvfiles: flask request files list :return: None. Raises a validation error if there are problems with the formatting """ table_name = sanitize_string(upload_form.get(DATA_SOURCE)) username = upload_form.get(USERNAME) notes = upload_form.get(NOTES) csv_sql_creator = CreateTablesFromCSVs( current_app.config[SQLALCHEMY_DATABASE_URI]) data = validate_wizard_upload_submission(table_name=table_name, csvfiles=csvfiles, csv_sql_creator=csv_sql_creator) ( upload_id, upload_time, table_name, ) = csv_sql_creator.create_and_fill_new_sql_table_from_df( table_name, data, REPLACE) # remove any existing metadata for this table name and write a new row SqlDataInventory.remove_metadata_rows_for_table_name(table_name) SqlDataInventory.write_upload_metadata_row( upload_id=upload_id, upload_time=upload_time, table_name=table_name, active=True, username=username, notes=notes, ) # Generate a new models.py # update the metadata to include all tables in the db csv_sql_creator.meta.reflect() # write the database schema to models.py generator = CodeGenerator(csv_sql_creator.meta, noinflect=True) # Write the generated model code to the specified file or standard output models_filepath = os.path.join(APP_DEPLOY_DATA, "models.py") # remove and write new file to trigger file watcher and refresh flask app if os.path.exists(models_filepath): os.remove(models_filepath) with io_open(os.path.join(models_filepath), "w", encoding="utf-8") as outfile: generator.render(outfile)
def main(): parser = argparse.ArgumentParser(description='Generates SQLAlchemy model code from an existing database.') parser.add_argument('url', nargs='?', help='SQLAlchemy url to the database') parser.add_argument('--version', action='store_true', help="print the version number and exit") parser.add_argument('--schema', help='load tables from an alternate schema') parser.add_argument('--tables', help='tables to process (comma-separated, default: all)') parser.add_argument('--noviews', action='store_true', help="ignore views") parser.add_argument('--noindexes', action='store_true', help='ignore indexes') parser.add_argument('--noconstraints', action='store_true', help='ignore constraints') parser.add_argument('--nojoined', action='store_true', help="don't autodetect joined table inheritance") parser.add_argument('--noinflect', action='store_true', help="don't try to convert tables names to singular form") parser.add_argument('--noclasses', action='store_true', help="don't generate classes, only tables") parser.add_argument('--outfile', help='file to write output to (default: stdout)') parser.add_argument('--nobackrefs', action='store_true', help="don't include backrefs") parser.add_argument('--flask', action='store_true', help="use Flask-SQLAlchemy columns") parser.add_argument('--ignore-cols', help="Don't check foreign key constraints on specified columns (comma-separated)") parser.add_argument('--nocomments', action='store_true', help="don't render column comments") args = parser.parse_args() if args.version: print(sqlacodegen.version) return if not args.url: print('You must supply a url\n', file=sys.stderr) parser.print_help() return engine = create_engine(args.url) import_dialect_specificities(engine) metadata = MetaData(engine) tables = args.tables.split(',') if args.tables else None ignore_cols = args.ignore_cols.split(',') if args.ignore_cols else None metadata.reflect(engine, args.schema, not args.noviews, tables) outfile = codecs.open(args.outfile, 'w', encoding='utf-8') if args.outfile else sys.stdout generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.nobackrefs, args.flask, ignore_cols, args.noclasses, args.nocomments) generator.render(outfile)
def main(): parser = argparse.ArgumentParser(description='Generates SQLAlchemy model code from an existing database.') parser.add_argument('url', nargs='?', help='SQLAlchemy url to the database') parser.add_argument('--version', action='store_true', help="print the version number and exit") parser.add_argument('--schema', help='load tables from an alternate schema') parser.add_argument('--tables', help='tables to process (comma-separated, default: all)') parser.add_argument('--noviews', action='store_true', help="ignore views") parser.add_argument('--noindexes', action='store_true', help='ignore indexes') parser.add_argument('--noconstraints', action='store_true', help='ignore constraints') parser.add_argument('--nojoined', action='store_true', help="don't autodetect joined table inheritance") parser.add_argument('--noinflect', action='store_true', help="don't try to convert tables names to singular form") parser.add_argument('--nobackrefs', action='store_true', help="don't include backrefs") parser.add_argument('--flask', action='store_true', help="use Flask-SQLAlchemy columns") parser.add_argument('--ignorefk', help="Don't check fk constraints on specified columns (comma-separated)") parser.add_argument('--outfile', type=argparse.FileType('w'), default=sys.stdout, help='file to write output to (default: stdout)') args = parser.parse_args() if args.version: print(sqlacodegen.version) return if not args.url: print('You must supply a url\n', file=sys.stderr) parser.print_help() return engine = create_engine(args.url) import_dialect_specificities(engine) metadata = MetaData(engine) tables = args.tables.split(',') if args.tables else None fkcols = args.ignorefk.split(',') if args.ignorefk else None metadata.reflect(engine, args.schema, not args.noviews, tables) generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.nobackrefs, args.flask, fkcols) generator.render(args.outfile)
def generate_code(metadata, **kwargs): codegen = CodeGenerator(metadata, **kwargs) sio = StringIO() codegen.render(sio) return remove_unicode_prefixes(sio.getvalue())
def generate_code(self, **kwargs): codegen = CodeGenerator(self.metadata, **kwargs) sio = StringIO() codegen.render(sio) return remove_unicode_prefixes(sio.getvalue())
def handle(self, *args, **options): version = options["version"] if not version: version = str(int(CONTENT_SCHEMA_VERSION) + 1) no_export_schema = version == CURRENT_SCHEMA_VERSION app_name = KolibriContentConfig.label if not no_export_schema: settings.DATABASES["default"] = { "ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:", } # Force a reload of the default connection after changing settings. del connections["default"] settings.INSTALLED_APPS = ("kolibri.core.content.contentschema", ) apps.app_configs = OrderedDict() apps.apps_ready = apps.models_ready = apps.loading = apps.ready = False apps.all_models = defaultdict(OrderedDict) apps.clear_cache() apps.populate(settings.INSTALLED_APPS) call_command("makemigrations", app_name, interactive=False) call_command("migrate", app_name) engine = create_engine(get_default_db_string(), poolclass=SharingPool, convert_unicode=True) metadata = MetaData() app_config = apps.get_app_config(app_name) # Exclude channelmetadatacache in case we are reflecting an older version of Kolibri table_names = [ model._meta.db_table for name, model in app_config.models.items() if name != "channelmetadatacache" ] metadata.reflect(bind=engine, only=table_names) Base = prepare_base(metadata, name=version) # TODO map relationship backreferences using the django names session = sessionmaker(bind=engine, autoflush=False)() metadata.bind = engine generator = CodeGenerator(metadata, False, False, True, True, False, nocomments=False) with io.open( SQLALCHEMY_CLASSES_PATH_TEMPLATE.format( name=coerce_version_name_to_valid_module_path(version)), "w", ) as f: generator.render(f) # Only do this if we are generating a new export schema version if not no_export_schema: # Load fixture data into the test database with Django call_command("loaddata", "content_import_test.json", interactive=False) data = {} for table_name, record in Base.classes.items(): data[table_name] = [ get_dict(r) for r in session.query(record).all() ] data_path = DATA_PATH_TEMPLATE.format(name=version) # Handle Python 2 unicode issue by opening the file in binary mode # with no encoding as the data has already been encoded if sys.version[0] == "2": with io.open(data_path, mode="wb") as f: json.dump(data, f) else: with io.open(data_path, mode="w", encoding="utf-8") as f: json.dump(data, f) shutil.rmtree( os.path.join(os.path.dirname(__file__), "../../contentschema/migrations")) os.system("kolibri manage generate_schema " + CURRENT_SCHEMA_VERSION)
def main(): parser = argparse.ArgumentParser( description='Generates SQLAlchemy model code from an existing database.' ) parser.add_argument('url', nargs='?', help='SQLAlchemy url to the database') parser.add_argument('--version', action='store_true', help="print the version number and exit") parser.add_argument('--schema', help='load tables from an alternate schema') parser.add_argument( '--tables', help='tables to process (comma-separated, default: all)') parser.add_argument('--noviews', action='store_true', help="ignore views") parser.add_argument('--noindexes', action='store_true', help='ignore indexes') parser.add_argument('--noconstraints', action='store_true', help='ignore constraints') parser.add_argument('--nojoined', action='store_true', help="don't autodetect joined table inheritance") parser.add_argument( '--noinflect', action='store_true', help="don't try to convert tables names to singular form") parser.add_argument('--noclasses', action='store_true', help="don't generate classes, only tables") parser.add_argument('--outfile', help='file to write output to (default: stdout)') parser.add_argument( '--table_backref_file', help= 'CSV file with source table, target table, and back relationship name') parser.add_argument( "--add_version", action='store_true', help= 'Adds version to printed model as a constant. Version is found querying the "version" table. There is no current way of modifying this besides chanfing the script.', ) args = parser.parse_args() if args.version: version = pkg_resources.get_distribution('sqlacodegen').parsed_version print(version.public) return if not args.url: print('You must supply a url\n', file=sys.stderr) parser.print_help() return # Use reflection to fill in the metadata engine = create_engine(args.url) metadata = MetaData(engine) session = sessionmaker(bind=engine)() tables = args.tables.split(',') if args.tables else None metadata.reflect(engine, args.schema, not args.noviews, tables) # take care of the backref hack backrefs_tables = None if args.table_backref_file: backref_file = pathlib.Path(args.table_backref_file) backrefs_tables = load_backref_csv(backref_file) # Check if we need to add the version version = None if args.add_version: version = session.query(metadata.tables["version"]).all()[0][0] # Write the generated model code to the specified file or standard output outfile = io.open(args.outfile, 'w', encoding='utf-8') if args.outfile else sys.stdout generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses, backrefs_tables, model_version=version) generator.render(outfile)
def main(): parser = argparse.ArgumentParser(description='Generates SQLAlchemy model code from an existing database.') parser.add_argument('url', nargs='?', help='SQLAlchemy url to the database') parser.add_argument('--version', action='store_true', help="print the version number and exit") parser.add_argument('--schema', help='load tables from an alternate schema') parser.add_argument('--tables', help='tables to process (comma-separated, default: all)') parser.add_argument('--noviews', action='store_true', help="ignore views") parser.add_argument('--noindexes', action='store_true', help='ignore indexes') parser.add_argument('--noconstraints', action='store_true', help='ignore constraints') parser.add_argument('--nojoined', action='store_true', help="don't autodetect joined table inheritance") parser.add_argument('--noinflect', action='store_true', help="don't try to convert tables names to singular form") parser.add_argument('--noclasses', action='store_true', help="don't generate classes, only tables") parser.add_argument('--outfile', help='file to write output to (default: stdout)') parser.add_argument('--audited', help='comma separated list of audited table names') parser.add_argument('--auditall', action='store_true', help='audit all tables') parser.add_argument('--relationship', action='append', nargs=4, metavar=('parent', 'child', 'name', 'kwargs'), help='Creates an association with the specified name') parser.add_argument('--loginuser', help='Model name that will instantiate the flask-login "UserMixin" (default: none)') parser.add_argument('--loginrole', help='Model name that will instantiate the flask-login "UserRole" (default: none)') parser.add_argument('--columntype', action='append', nargs=3, metavar=('table', 'old_type', 'new_type'), help='TODO') args = parser.parse_args() if args.version: version = pkg_resources.get_distribution('sqlacodegen').parsed_version print(version.public) return if not args.url: print('You must supply a url\n', file=sys.stderr) parser.print_help() return _relationship = dict() _rel_set = set() args.relationship = [] if args.relationship is None else args.relationship for (key, child, name, kwargs) in args.relationship: val = { 'child' : child, 'name' : name, 'kwargs' : json.loads(kwargs) } if not (key in _relationship): _relationship[key] = [] # There must not be conflicts where a table is given # forced relationships that share an an attribute name if (key, name) in _rel_set: raise KeyError(f'Tried to create a forced relationship "{name}" ' +f'within {key}, but another forced relationship ' +f'exists in {key} with the same name.') _rel_set.add((key, name)) _relationship[key].append(val) args.relationship = _relationship engine = create_engine(args.url) metadata = MetaData(engine) tables = args.tables.split(',') if args.tables else None metadata.reflect(engine, args.schema, not args.noviews, tables) outfile = codecs.open(args.outfile, 'w', encoding='utf-8') if args.outfile else sys.stdout if args.audited: args.audited = set(args.audited.split(',')) args.columntype = [] if args.columntype is None else args.columntype generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses, audited=args.audited, audit_all=args.auditall, flask_login_user=args.loginuser, flask_login_role=args.loginrole, force_relationship=args.relationship, special_column_types=args.columntype) generator.render(outfile)
def main(): parser = argparse.ArgumentParser( description="Generates SQLAlchemy model code from an existing database." ) parser.add_argument("url", nargs="?", help="SQLAlchemy url to the database") parser.add_argument("--version", action="store_true", help="print the version number and exit") parser.add_argument("--schema", help="load tables from an alternate schema") parser.add_argument( "--tables", help="tables to process (comma-separated, default: all)") parser.add_argument("--noviews", action="store_true", help="ignore views") parser.add_argument("--noindexes", action="store_true", help="ignore indexes") parser.add_argument("--noconstraints", action="store_true", help="ignore constraints") parser.add_argument("--nojoined", action="store_true", help="don't autodetect joined table inheritance") parser.add_argument( "--noinflect", action="store_true", help="don't try to convert tables names to singular form") parser.add_argument("--noclasses", action="store_true", help="don't generate classes, only tables") parser.add_argument("--outfile", help="file to write output to (default: stdout)") args = parser.parse_args() if args.version: version = pkg_resources.get_distribution("sqlacodegen").parsed_version print(version.public) return if not args.url: print("You must supply a url\n", file=sys.stderr) parser.print_help() return # Use reflection to fill in the metadata engine = create_engine(args.url) try: # dirty hack for sqlite engine.execute("""PRAGMA journal_mode = OFF""") except: pass metadata = MetaData(engine) tables = args.tables.split(",") if args.tables else None metadata.reflect(engine, args.schema, not args.noviews, tables) # Write the generated model code to the specified file or standard output outfile = io.open(args.outfile, "w", encoding="utf-8") if args.outfile else sys.stdout generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses) generator.render(outfile)
def main(): parser = argparse.ArgumentParser(description='Generates SQLAlchemy model code from an existing database.') parser.add_argument('url', nargs='?', help='SQLAlchemy url to the database') parser.add_argument('--version', action='store_true', help="print the version number and exit") parser.add_argument('--schema', help='load tables from an alternate schema') parser.add_argument('--tables', help='tables to process (comma-separated, default: all)') parser.add_argument('--noviews', action='store_true', help="ignore views") parser.add_argument('--noindexes', action='store_true', help='ignore indexes') parser.add_argument('--noconstraints', action='store_true', help='ignore constraints') parser.add_argument('--nojoined', action='store_true', help="don't autodetect joined table inheritance") parser.add_argument('--noinflect', action='store_true', help="don't try to convert tables names to singular form") parser.add_argument('--noclasses', action='store_true', help="don't generate classes, only tables") parser.add_argument('--outfile', help='file to write output to (default: stdout)') parser.add_argument('--audited', help='comma separated list of audited table names') parser.add_argument('--auditall', action='store_true', help='audit all tables') parser.add_argument('--relationship', action='append', nargs=3, metavar=('parent', 'child', 'name'), help='Creates an association with the specified name') args = parser.parse_args() if args.version: version = pkg_resources.get_distribution('sqlacodegen').parsed_version print(version.public) return if not args.url: print('You must supply a url\n', file=sys.stderr) parser.print_help() return _relationship = dict() for rel in args.relationship: key = rel[0] val = { 'child' : rel[1] ,'name' : rel[2] } if not (key in _relationship): _relationship[key] = [] _relationship[key].append(val) args.relationship = _relationship engine = create_engine(args.url) metadata = MetaData(engine) tables = args.tables.split(',') if args.tables else None metadata.reflect(engine, args.schema, not args.noviews, tables) outfile = codecs.open(args.outfile, 'w', encoding='utf-8') if args.outfile else sys.stdout if args.auditall: generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses, audit_all=args.auditall, force_relationship=args.relationship) elif args.audited: generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses, audited=set(args.audited.split(',')), force_relationship=args.relationship) else: generator = CodeGenerator(metadata, args.noindexes, args.noconstraints, args.nojoined, args.noinflect, args.noclasses, force_relationship=args.relationship) generator.render(outfile)