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
Related
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)
)
I am trying to use SQLAlchemy automap to map an existing MSSQL view. I can successfully automap a table and perform queries against it but as soon as I target a view it fails. Here is some code of a couple of different attempts I have tried.
Mapping a standard table works with the following:
engine = create_engine("mssql+pyodbc://username:password#serv.example.com/db?driver=ODBC+Driver+13+for+SQL+Server")
metadata = MetaData()
metadata.reflect(engine, only=['table_name'])
Base = automap_base(metadata=metadata)
Base.prepare()
table = Base.classes.table_name
Mapping a view with the following fails
engine = create_engine("mssql+pyodbc://username:password#serv.example.com/db?driver=ODBC+Driver+13+for+SQL+Server")
metadata = MetaData()
metadata.reflect(engine, only=['view_name'], views=True)
Base = automap_base(metadata=metadata)
Base.prepare()
view = Base.classes.view_name
EDIT: I have now tried to create a class which maps a unique column as the primary key but I am still getting errors. Here is what I am trying.
Base.automap()
class view_name(Base):
__tablename__ = 'view_name'
some_id = Column('some_id', Integer, primary_key=True)
engine = create_engine("mssql+pyodbc://username:password#serv.example.com/db?driver=ODBC+Driver+13+for+SQL+Server")
metadata = MetaData()
metadata.reflect(engine, only=['view_name'], views=True)
Base.prepare()
view = Base.classes.view_name
And I am now getting the following error.
AttributeError: view_name
Here's what worked for me.
from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine, MetaData, Column, Integer, Table
from sqlalchemy.orm import Session
Base = automap_base()
conn_str = '...'
engine = create_engine(conn_str)
metadata = MetaData()
# you only need to define which column is the primary key. It can automap the rest of
the columns.
viewname = Table('view_name',metadata, Column('some_id', Integer,
primary_key=true), autoload=True, autoload_with=engine)
Base.prepare()
view_name = Base.classes.view_name
session = Session(engine)
v1 = session.query(view_name).first()
For anyone who still can get it working try this:
Table('view_name',Base.metadata, Column('some_id', Integer,
primary_key=True), autoload=True, autoload_with=engine)
Base.prepare(engine, reflect=True)
I have a test database with two entities: post and category and I'm using declarative base to perform the manipulation of the data in my base, as follows:
engine = create_engine("sqlite:///test.db")
Base = declarative_base()
Base.metadata.bind = engine
class Post(Base):
__tablename__ = "post"
post_id = Column('id', primary_key=True)
title = Column('title')
...other attributes...
class Category(Base):
__tablename__ = "category"
category_id = Column('id', primary_key=True)
description = Column('name')
...other attributes...
Assuming I wanted to create a relationship between post and category (which does not exist in my database), how do I create it? Any idea?
Edit1:
I'll try to be clearer: the database already exists where a bind is done, as well as the post and category tables. What I want is to create a relationship between them through the code and write this in the database
create_all method support specify tables to create:
Base.metadata.create_all(tables=[Post.__table__,])
result:
$ sqlite3 test.db
sqlite> .tables
post
I've reflected an existing database and overwritten some columns.
Can someone tell me what's wrong with the following?
metadata = MetaData(engine)
class User(Base):
__tablename__ = 'users'
__table__ = Table('dim_user', metadata,
Column('user_id', Integer, primary_key=True),
autoload=True)
projects = relationship('Project', back_populates='users')
class Project(Base):
__tablename__ = 'projects'
__table__ = Table('dim_project', metadata,
Column('project_id', Integer, primary_key=True),
Column('user_id', Integer, ForeignKey('users.user_id')),
autoload=True)
When I try to query anything I get:
NoForeignKeysError: Could not determine join condition between parent/child tables on relationship User.projects - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
As #ilja-everilä already tried to convey in his comment, your model is not consitent: you are explicitly defining __table__ properties, which override then __tablename__ properties -- you have to find out which of the are the right ones. In your ForeignKey definition you refer to the __tablename__ of User but not the __table__ definition.
In your relationship definition of User.projects you don't explicitly refer a ForeigKey nor a join condition, and since your meta data is messed up (see above) sqlalchemy is unable to determine automatically what you want.
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')