On 9/21/15 3:04 PM, Sergi Pons Freixes wrote:


2015-09-21 10:42 GMT-07:00 Sergi Pons Freixes <sachiel2...@gmail.com <mailto:sachiel2...@gmail.com>>:


    2015-09-19 8:18 GMT-07:00 Mike Bayer <mike...@zzzcomputing.com
    <mailto:mike...@zzzcomputing.com>>:

        what is your search_path set to ?   see
        
http://docs.sqlalchemy.org/en/rel_1_0/dialects/postgresql.html#remote-schema-table-introspection-and-postgresql-search-pathfor
        background on this.    It is highly recommended that
        search_path remain set on "public" and that you do *not*
        refer to the "public" name directly in any table
        definitions.   Feel free to share a model that includes all
        the tables and constraints in question as well.


    If I understood it correcty, we're not setting search_path. Sample
    with pyramid's pshell:


search path is not in Python, it's in your database.    Please run this:



classics-MacBook-Pro:openvpn classic$ psql -U scott test
psql (9.4.0)
Type "help" for help.

test=> show search_path;
  search_path
----------------
 "$user",public
(1 row)





    -----------8<--------------
    $ pshell development.ini
    In [1]: from notifications.models import *

    In [2]: Base.metadata.schema is None
    Out[2]: True

    In [3]: Base.metadata.tables['notifications.email_attachment'].schema
    Out[3]: 'notifications'
    -----------8<--------------

    We're only using "public" for the alembic_versions table, all the
    rest are on the same schema ("notifications" in this case).


Ok, I have a simpler test case. Just changing the schema from "public" to "notifications" triggers the issue.

On the issue-free case, my nofications.email.models.py <http://nofications.email.models.py> is:
-----------8<--------------
from sqlalchemy import Column, Integer, ForeignKey

from notifications.sqla_base import Base

class t1(Base):
    __tablename__='t1'
    __table_args__ = {'schema': 'public'}






    def __init__(self):
        pass

class t2(Base):
    __tablename__='t2'
    __table_args__ = {'schema': 'public'}
    t1id = Column('t1id', Integer, ForeignKey(t1.id <http://t1.id>))

    def __init__(self, t1id=None):
        self.t1id = t1id
-----------8<--------------

A first run of 'alembic -c development.ini revision -m "upgrade" --autogenerate' creates the tables as expected:
-----------8<--------------
...
def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.create_table('t1',
    sa.Column('fxt', sa.String(), nullable=True),
    sa.Column('id', sa.Integer(), nullable=False),
    sa.PrimaryKeyConstraint('id'),
    schema='public'
    )
    op.create_table('t2',
    sa.Column('t1id', sa.Integer(), nullable=True),
    sa.Column('foo', sa.Integer(), nullable=True),
    sa.Column('fxt', sa.String(), nullable=True),
    sa.Column('id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['t1id'], ['public.t1.id <http://public.t1.id>'], ),
    sa.PrimaryKeyConstraint('id'),
    schema='public'
    )
    ### end Alembic commands ###
...
-----------8<--------------

And a second run does nothing, also as expected:
-----------8<--------------
...
def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    pass
    ### end Alembic commands ###
...
-----------8<--------------

But, when changing my model so that "__table_args__ = {'schema': 'notifications'}", the outputs of alembic are:

First run (fine):
-----------8<--------------
...
def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.create_table('t1',
    sa.Column('fxt', sa.String(), nullable=True),
    sa.Column('id', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id'),
    schema='notifications'
    )
    op.create_table('t2',
    sa.Column('t1id', sa.Integer(), nullable=True),
    sa.Column('foo', sa.Integer(), nullable=True),
    sa.Column('fxt', sa.String(), nullable=True),
    sa.Column('id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['t1id'], ['notifications.t1.id <http://notifications.t1.id>'], ),
sa.PrimaryKeyConstraint('id'),
    schema='notifications'
    )
    ### end Alembic commands ###
...
-----------8<--------------

Second run (oops!):
-----------8<--------------
...
def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint('t2_t1id_fkey', 't2', type_='foreignkey')
op.create_foreign_key(None, 't2', 't1', ['t1id'], ['id'], source_schema='notifications', referent_schema='notifications')
    ### end Alembic commands ###
...
-----------8<--------------

On both cases, env.py was:
-----------8<--------------
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config
from pyramid.paster import setup_logging

import notifications.models
from notifications.sqla_base import DBSession, Base

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
setup_logging(config.config_file_name)
engine = engine_from_config(config.get_section('app:main'), 'sqlalchemy.')
DBSession.configure(bind=engine)

target_metadata = Base.metadata

def run_migrations_offline():
    ...

def run_migrations_online():
    connection = engine.connect()
    context.configure(
        connection=connection,
target_metadata=target_metadata,
        include_schemas=True,
version_table_schema='public'
    )
    try:
        with context.begin_transaction():
context.run_migrations()
    finally:
        connection.close()

if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()
-----------8<--------------

Where notifications.models just has a "from notifications.email.models import *" statement, and notifications.sql_base.py <http://notifications.sql_base.py>:
-----------8<--------------

from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import (
    scoped_session,
    sessionmaker,
)
from sqlalchemy import Column, Integer, String
from zope.sqlalchemy import ZopeTransactionExtension

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))

class NotificationsBase:
    @declared_attr
    def id(cls):
        return Column(Integer, primary_key=True)

    @declared_attr
    def fxt(cls):
        return Column(String, nullable=True)

    @classmethod
    def get_one(cls, **kwargs):
        query = DBSession.query(cls)
        for k, v in kwargs.items():
            query = query.filter(getattr(cls, k) == v)
        return query.one()

    def __repr__(self):
return "<%s id=%s>" % (self.__class__.__name__, self.id <http://self.id>)

Base = declarative_base(cls=NotificationsBase)
-----------8<--------------

So, yes, it is definitely related with the schema.
--
You received this message because you are subscribed to the Google Groups "sqlalchemy-alembic" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy-alembic+unsubscr...@googlegroups.com <mailto:sqlalchemy-alembic+unsubscr...@googlegroups.com>.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy-alembic" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy-alembic+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to