Generate database schema using SQLAlchemy [duplicate] - python

This question already has answers here:
SQLAlchemy printing raw SQL from create()
(6 answers)
Closed 3 years ago.
I have a very simple One-to-Many database schema (a parent can have many children but a child can only have one parent). My SQLAlchemy models looks like so:
from sqlalchemy import Table, Column, Integer, ForeignKey
from sqlalchemy.orm import relationship
from models import Base
class Parent(Base):
__tablename__ = 'Parent'
id = Column(Integer, primary_key=True)
children = relationship('Child', backref='parent')
class Child(Base):
__tablename__ = 'Child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('Parent.id'))
I'm able to create the tables in the database using the following commands:
engine = create_engine('mysql://localhost:3306/testdb')
Base.metadata.create_all(engine)
I'm curious what the raw SQL looks like to create these tables. I'd imagine it would look something like this, but I would like to be sure:
CREATE TABLE Parent (
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
);
CREATE TABLE Child (
id INT NOT NULL AUTO_INCREMENT,
parent_id int,
PRIMARY KEY (id),
CONSTRAINT FK_Parent FOREIGN KEY (parent_id) REFERENCES Parent(id)
);
Is there anyway to generate the database schema in raw sql using SQLAlchemy? I know I can generate a query in raw sql but I'm wondering how to generate the initial database schema.
On top of that, is there anyway to generate the schema depending on the actual database type (e.g. the raw sql would look slightly different for MySQL and PostgreSQL)?

how-can-i-get-the-create-table-drop-table-output-as-a-string
from sqlalchemy import MetaData, Table, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import CreateTable
import sqlalchemy
print(sqlalchemy.__version__)
Base = declarative_base()
class Parent(Base):
__tablename__ = 'Parent'
id = Column(Integer, primary_key=True)
children = Column(String(255))
user = Table('users', MetaData(bind=None),
Column('id', Integer(), primary_key=True, nullable=False),
Column('name', String()),
Column('fullname', String()),
Column('password', String()), schema=None)
print(CreateTable(Parent.__table__))
print(CreateTable(user))
Output:
1.3.0b1
CREATE TABLE "Parent" (
id INTEGER NOT NULL,
children VARCHAR(255),
PRIMARY KEY (id)
)
CREATE TABLE users (
id INTEGER NOT NULL,
name VARCHAR,
fullname VARCHAR,
password VARCHAR,
PRIMARY KEY (id)
)

Related

SQLAlchemy Relationships - Beginners traps

i started learning python3 with SQLAlchemy. No i created a quick example Database with a User Table and an Group Table.
CREATE TABLE `USER` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(255) NOT NULL,
`USERNAME` varchar(255) NOT NULL,
`group_id` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `fk_groups_idx` (`group_id`),
CONSTRAINT `fk_groups` FOREIGN KEY (`group_id`) REFERENCES `GROUPS` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
CREATE TABLE `GROUPS` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`GroupName` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
Quick and dirty, just for learning it. Every User is in a group (not multiple) and every Group can relate to many user.
So it is an Many-to-one relationship if i am not wrong.
To build my Relationship bidirectional (with the example from SqlAlchemy) i have to back_populate both classes in my mapping. But when i start my test, i get the following message:
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship Groups.users - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specifya 'primaryjoin' expression.
My code is just on script for testing. Maybe someone with more experience could point me to my problem:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import sessionmaker
from datetime import datetime, timedelta
from sqlalchemy import Table, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import PrimaryKeyConstraint
from sqlalchemy import ForeignKeyConstraint
Base = declarative_base()
class User(Base):
__tablename__ = 'USER'
ID = Column('ID', Integer, primary_key=True)
name = Column('NAME',String)
username = Column('USERNAME', String)
group_id = Column('group_id', Integer, ForeignKey('group_id'))
group = relationship("Groups", back_populates="users")
class Groups(Base):
__tablename__ = 'GROUPS'
id = Column('id', Integer, primary_key=True)
groupName = Column('GroupName', String)
users = relationship("User", back_populates="group")
engine = create_engine('mysql://test:test#localhost/TEST')
Session = sessionmaker(bind=engine)
session = Session()
for instance in session.query(User).order_by(User.ID):
print(instance.ID, instance.username, instance.group_id)
session.close();
Regards
Issue is with foreign key declaration for group_id and it can be done like below to resolve error - sqlalchemy.exc.NoForeignKeysError
group_id = Column('group_id', Integer, ForeignKey('GROUPS.id'))

Create table in Oracle with auto-increment field using Sqlalchemy

I am creating a table in my Oracle DB using python and sqlalchemy. I would like to have an auto-increment ID column as primary key. How can I modify the following code to add the autoload option or anything like that ?
engine = creat_engine("oracle:// ....")
Base = declarative_base()
class MyTable(Base):
__tablename__ = 'MyTable'
ID = Column(Integer, Sequence('my_id_seq'), primary_key=True)
SomeColumn = Column(VARCHAR(50))
Base.metadata.create_all(engine)
p.s. I don't want to create a separate sequence and trigger (as shown here).
UPDATE:
when trying to do the following, I get syntax error because of "autoload=True":
class MyTable(Base):
__table__ = Table('myTable', Base.metadata, autoload=True,
Column('id', Integer, Sequence('my_id_seq'), primary_key=True),
Column('somecolumn', VARCHAR(50))
)
SyntaxError: non-keyword arg after keyword arg

Python & SQLAlchemy many-to-many relation error after specify schema name

Here the code:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
AvailableModules = db.Table('available_modules',
db.Column('customer_id', db.Integer, db.ForeignKey('customers.id')),
db.Column('module_id', db.Integer, db.ForeignKey('modules.id')),
schema='tcloud_admin')
class Customer(db.Model):
__tablename__ = 'customers'
__table_args__ = {"schema":"tcloud_admin"}
id = db.Column(db.Integer, primary_key=True)
....
modules = db.relationship('Module', secondary=AvailableModules)
class Module(db.Model):
__tablename__ = 'modules'
__table_args__ = {"schema":"tcloud_admin"}
id = db.Column(db.Integer, primary_key=True)
....
Trying the above script gives me this error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with
column 'available_modules.customer_id' could not find table
'customers' with which to generate a foreign key to target column 'id'
Without specifying the schema name everything works fine.
When using a custom schema name all foreign keys that reference a table or column in that schema must explicitly contain that schema name too.
Your ForeignKey('customers.id') references a different table customers which is not inside your custom schema. As this table does not exist at all you get the corresponding error.
To fix the error change the foreign keys:
db.ForeignKey('tcloud_admin.customers.id')
db.ForeignKey('tcloud_admin.modules.id')
This is also explained in the docs

sqlalchemy.exc.AmbiguousForeignKeysError after Inheritance

I'm using sqlacodegen for reflecting a bunch of tables from my database.
And i'm getting the following error:
sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'Employee' and 'Sales'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.
Here's a simplified version of my tables.
I read in the documentation that I should use the foreign_keys parameter to resolve ambiguity between foreign key targets. Although, I think this problem is because of the inheritance. Could someone help me understand what is going on.
# coding: utf-8
from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Employee(Base):
__tablename__ = 'Employee'
EmployeeId = Column(Integer, primary_key=True)
class Sales(Employee):
__tablename__ = 'Sales'
EmployeeID = Column(ForeignKey('Employee.EmployeeId'), primary_key=True)
OldemployeeID = Column(ForeignKey('Employee.EmployeeId'))
employee = relationship('Employee', foreign_keys=[EmployeeID])
old_employee = relationship("Employee", foreign_keys=[OldemployeeID])
When your tables have multiple possible paths to inherit between them (Sales.EmployeeID or Sales.OldEmployeeID), SqlAlchemy doesn't know which one to use and you'll need to tell it the path explicitly, by using inherit_condition. For instance to inherit by EmployeeID:
class Sales(Employee):
...
__mapper_args__ = { "inherit_condition": EmployeeID == Employee.EmployeeId }
For the sake of example, you could also inherit by OldEmployeeID, by entering OldEmployeeID == Employee.EmployeeId - this would mean that both your Sales primary key and the Employee primary key are allowed to be different.
Just use backref and use Integer on both EmployeeID and OldemployeeID. Otherwise you will get an another error.
class Sales(Employee):
__tablename__ = 'Sales'
EmployeeID = Column(Integer, ForeignKey('Employee.EmployeeId'), primary_key=True)
OldemployeeID = Column(Integer, ForeignKey('Employee.EmployeeId'))
employee = relationship('Employee', foreign_keys=[EmployeeID], backref='Employee')
old_employee = relationship("Employee", foreign_keys=[OldemployeeID], backref='Employee')

Can only define secondary relationship using association table object but not name

Trying to create an association relationship between the classes Note and Document. The problem I'm facing is that my secondary relationship only works when I use the association table object and not that table name. What I mean is that the relationship:
notes = relationship(u'Note', secondary=t_Documented, backref='documents')
works but the following does NOT work:
notes = relationship(u'Note', secondary='Documented', backref='documents')
When querying, I get the error:
sqlalchemy.exc.InvalidRequestError: When initializing mapper
Mapper|Document|Document, expression 'Documented' failed to locate a
name ("name 'Documented' is not defined"). If this is a class name,
consider adding this relationship() to the
class after both dependent classes have been defined.
I would rather use the name as my model is generated using sqlacodegen.
Moreover, SQLAlchemy docs say I can use the name (http://docs.sqlalchemy.org/en/rel_0_9/orm/relationships.html#many-to-many) with caveta "with the declarative extension in use". I Googled the term which led me to this. Question is how in my case can I augment the Base.
# model.py
# coding: utf-8
from sqlalchemy import Column, Date, DateTime, ForeignKey, ForeignKeyConstraint, Index, Integer, Numeric, String, Table, Text, text
from sqlalchemy.orm import backref, relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
metadata = Base.metadata
t_Documented = Table(
'Documented', metadata,
Column('id', Integer, primary_key=True),
Column('note_id', ForeignKey(u'MySchema.Note.id'), nullable=False),
Column('document_id', ForeignKey(u'MySchema.Document.id'), nullable=False, index=True),
Column('inserted', DateTime, nullable=False, server_default=text("'0000-00-00 00:00:00'")),
Column('updated', DateTime, nullable=False, server_default=text("'0000-00-00 00:00:00'")),
Index('Documented_AK1', 'note_id', 'document_id'),
schema='MySchema'
)
class Note(Base):
__tablename__ = 'Note'
__table_args__ = {u'schema': 'MySchema'}
id = Column(Integer, primary_key=True)
class Document(Note):
__tablename__ = 'Document'
__table_args__ = {u'schema': 'MySchema'}
id = Column(ForeignKey(u'MySchema.Note.id'), primary_key=True)
title = Column(String(100), nullable=False)
author = Column(String(100), nullable=False)
notes = relationship(u'Note', secondary='Documented', backref='documents')
Using SQLAlchemy 0.9.4 and Python 2.6.6. Connector is MySQLDB and I'm using MySQL database.
your table has a schema of "MySchema" so that has to be part of it:
notes = relationship(u'Note', secondary='MySchema.Documented', backref='documents')

Categories