How to create a mssql VIEW model using flask-migrate? - flask-migrate

Mssql+pyodbc connection.
Imports and db
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Table, text, Text, Unicode, MetaData
from sqlalchemy.orm import relationship
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
I have generated table models using flask-sqlacodegen which look like this
class BlaBla(db.Model):
__tablename__ = 'bla_bla'
blabla= db.Column(db.Integer, primary_key=True)
bla2= db.Column(db.Integer, nullable=False)
The view that I have in the db was generated like this
t_bla_bla_bla_view = Table(
'View_bla_bla_bla',
Column('irrelevant', db.Unicode(50), nullable=False),
Column('etc', db.Unicode(50), nullable=False),
Column('etc2', db.Unicode(50), nullable=False)
)
When I run flask db migrate, the tables are properly created, while the View is also created as a table.
What is the actual syntax on creating a view?
Maybe there is a raw query migrate workaround?

Related

Postgres connection string with schema, alembic sqlalchemy

I am working on Alembic with SQLAlchemy on my Alembic.ini I am setting my postgres connection string but it goes to my public schema, i need to choose my schema.
How I can use an specific schema:
alembic.ini file
sqlalchemy.url = postgresql://myuser:mypassword#server:host/database
models.py
import datetime
from sqlalchemy import Column,Integer,String,DateTime,create_engine
from sqlalchemy.orm import declarative_base,sessionmaker
Base = declarative_base()
class UserModel(Base):
__tablename__='myschema.person'
id = Column(Integer, primary_key=True)
first_name = Column(String, nullable=False)
last_name = Column(String, nullable = False)
birth = Column(DateTime)
This connection string works with public, I need to connect to my "sales" schema.
On my models.py I am just creating a table person, I tried adding there Core schema but didn't works
Regards
Here you can find a complete working example
Define schema on your model
class A(Base):
__tablename__ = 'a'
__table_args__ = {
"schema": "alphabet"
}
edit env.py to work with schemas
with connectable.connect() as connection:
"""
Configure migration context
1. Pass our models metadata
2. Set schema for alembic_version table
3. Load all available schemas
"""
context.configure(
connection=connection,
target_metadata=target_metadata,
"""
here you are passing schema
"""
version_table_schema=target_metadata.schema,
include_schemas=True
)
Run alembic revision and upgrade and it will work

how to update foreign keys in a different table after foreign key element was created in postgres with sqlalchemy

I have 2 tables with a one to many relationship. Parent can have many children, a child can only have one parent.
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Parent(Base):
__tablename__ = "parent"
id = Column(UUID(as_uuid=True), primary_key=True, index=True, nullable=False, default=uuid.uuid4)
children_ids = Column(postgres.ARRAY(Text), server_default=postgres.array("{}"))
class Child(Base):
__tablename__ = "child"
id = Column(UUID(as_uuid=True), primary_key=True, index=True, default=uuid.uuid4)
parent_id = Column(UUID, ForeignKey('Parent.id', ondelete='CASCADE'), nullable=False)
parent = relationship("Parent", backref=backref("child", passive_deletes=True, passive_updates=True))
I currently create a child entity with the session maker and use add() and commit(). I then have to manually update the parent entity and push/append the Child.id into the children_ids column. Is there a way how sqlalchemy can trigger a manual update or do I always have to manually update?

SQLAlchemy Joined Table Inheritance: Problem adding objects

I'm having problems trying to add inherited objects with SQLAlchemy following the instructions in https://docs.sqlalchemy.org/en/14/orm/inheritance.html to implement Joined Table Inheritance.
I'm using a PostgreSQL version 14 as a database engine.
Here is my Base configuration:
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.automap import automap_base
db_string = os.environ['DB_STRING']
engine = create_engine(db_string)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = automap_base()
Base.query = db_session.query_property()
Base.prepare(engine, reflect=True)
Here is Instrument (parent class) definition:
from sqlalchemy import Column, String
from context_model.database import Base
class Instrument(Base):
__tablename__ = "instrument"
_id = Column(String, primary_key=True)
discriminator = Column(String)
__mapper_args__ = {
'polymorphic_identity': 'instrument',
'polymorphic_on': discriminator
Here is Bond (child class) definition:
import datetime as dt
from sqlalchemy import Column, Integer, Float, String, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from context_model.instrument.instrument import Instrument
class Bond(Instrument):
__tablename__ = "bond"
_id = Column(String, ForeignKey("instrument._id"), primary_key=True)
_provider_bbg_id = Column(String)
__mapper_args__ = {
'polymorphic_identity': 'bond'
}
When I try to add a Bond instance and persist it to the database:
Bond = Base.classes.bond
bond = Bond()
bond._id = "0"
bond._provider_bbg_id = "XXX"
db_session.add(bond)
db_session.commit()
appears the following error message:
sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "bond" violates foreign key constraint "bond__id_fkey"
DETAIL: Key (_id)=(0) is not present in table "instrument"."
It seems to me that the inheritance is not working for some reason, did I define well the Instrument (parent) and Bond (child) classes ?, maybe do I need to use another type of Base ? (I'm using automap_base )
Thanks in advance for your help!
I don't know the exact reasons but I changed from declarative_base() to automap_base() as #snakecharmerb suggested in the commentaries and now it works :)

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) function st_geogfromtext(unknown) does not exist

I'm trying to create a table with geography data using geoalchemy2 with sqlalchemy following the geoalchemy ORM tutorial
I have the postgis extension installed on the schema I'm using. The user I'm connecting with is owner of the schema.
When I run the python code:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from geoalchemy2 import Geography
import src.config as config
Base = declarative_base()
class Lake(Base):
__tablename__ = 'lake'
__table_args__ = ({'schema': 'geobox'})
id = Column(Integer, primary_key=True)
country_iso_code = Column(String(2))
zone_code = Column(String(45))
zone_type = Column(String(45))
zone_test = Column(Geography('POINT'))
from sqlalchemy import create_engine
engine = create_engine('postgres://{user}:{pwd}#{host}:{port}/{database}'.format(
user=config.DbConfig().username,
pwd=config.DbConfig().password,
host=config.DbConfig().host,
port=config.DbConfig().port,
database=config.DbConfig().database), echo=True)
Lake.__table__.create(engine)
I get the error:
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) type "geography" does not exist
What am I missing here ?
I found out the search_path was not properly set, since the postgis had been installed at the table level and not at the schema level.
Not related to sqlalchemy then. I just needed to change the search_path to let pg find the table where postgis is installed with:
ALTER ROLE "my_role_name" SET search_path TO 'my_table_name',"$user",public;
(assuming my_table_name is the name of the table where the postgis extension has been installed)

ENUM type in SQLAlchemy with PostgreSQL

I'm using SQLAlchemy core with a postgresql database and I would like to add the ENUM type to my table definition. According to the postgresql documentation, the ENUM type must be defined prior to the table being created:
CREATE TYPE gender_enum AS ENUM ('female', 'male');
CREATE TABLE person (
name VARCHAR(20),
gender gender_enum
);
The problem is when I'm creating the table definition. After reading the SQLAlchemy documentation I couldn't find any implementation examples. I've tried something like this but it didn't work:
from sqlalchemy.dialects.postgresql import ENUM
person = Table('user_profile', metadata,
Column('name', String(20)),
Column('gender', ENUM('female', 'male'))
);
How it must be done?
You need to import Enum from sqlalchemy and add a name to it. It should work like this:
from sqlalchemy import Enum
person = Table("user_profile", metadata,
Column("name", String(20)),
Column("gender", Enum("female", "male", name="gender_enum", create_type=False))
);
#Tim's answer is definitely correct but I wanted to offer the way I setup my ENUMs.
In my models.py I will create the values as tuples
skill_levels = ('Zero', 'A little', 'Some', 'A lot')
Then I will create a skill_level_enum variable and assign it an ENUM class with the skill level values as args.
skill_level_enum = ENUM(*skill_levels, name="skill_level")
In my table model then I pass in the skill_level_enum
class User(db.Model):
id = db.Column(db.Integer(), primary_key=True)
skill_level = db.Column(skill_level_enum)
I have found this makes my code a lot cleaner and I'm able to make updates to the skill_levels at the top of my file rather than scanning my models for the right thing to update.
You can use Python's native enums as the column type as well:
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.dialects.postgresql import ENUM as pgEnum
from enum import Enum, unique
#unique
class errorTypeEnum(Enum):
videoValidation = 'videoValidation'
audioValidation = 'audioValidation'
subtitleValidation = 'subtitleValidation'
db = SQLAlchemy()
class Error(db.Model):
serviceID = db.Column(db.String(20), primary_key=True)
timestamp = db.Column(db.DateTime, unique=False, nullable=False)
category = db.Column(pgEnum(errorTypeEnum), unique=False, nullable=False)
The code below worked for me on SQLAlchemy 1.3.11 and Postgres 12.0.
You must first create the Enum type in postgres before creating the user table. This can be done directly through sql statement.
CREATE TYPE permission AS ENUM ('READ_ONLY', 'READ_WRITE', 'ADMIN', 'OWNER');
Then set up the project model
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'user'
user_id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
access = db.Column(db.Enum('READ_ONLY', 'READ_WRITE', 'ADMIN', 'OWNER', name="permission"))