On 12/11/2015 07:47 PM, Gerald Thibault wrote:
> Is there a way to perform a Metadata.create_all() but have it only
> create the tables, without any of the FKs? And then create the FKs in
> one go after the fixture data has been loaded into the DB?

first off, this is unnecessary because the DDL system can now create
mutually-dependent foreign key constraints without any use of the
use_alter flag; ALTER TABLE ADD CONSTRAINT is used automatically when a
cycle is detected and this flag is legacy.

However, if you want to manually control this you can use the rules at
http://docs.sqlalchemy.org/en/latest/core/ddl.html#controlling-ddl-sequences
to achieve this effect.  You'd apply the AddConstraint object to all of
the ForeignKeyConstraint objects and then set them up with events.  Here
is an example:


from sqlalchemy import Column, MetaData, Integer, create_engine,
ForeignKey, ForeignKeyConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import event

convention = {
  "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
}

metadata = MetaData(naming_convention=convention)

Base = declarative_base(metadata=metadata)


class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)


class B(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)
    a_id = Column(ForeignKey('a.id'))

from sqlalchemy.schema import AddConstraint, DropConstraint

for table in Base.metadata.tables.values():
    for constraint in table.constraints:
        if isinstance(constraint, ForeignKeyConstraint):
            event.listen(Base.metadata, "after_create",
AddConstraint(constraint))
            event.listen(Base.metadata, "before_drop",
DropConstraint(constraint))


e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)


Base.metadata.create_all(e)

Base.metadata.drop_all(e)






> 
> On Friday, December 11, 2015 at 3:38:16 PM UTC-8, Michael Bayer wrote:
> 
> 
> 
>     On 12/11/2015 05:25 PM, Gerald Thibault wrote:
>     > I am basing my question off the code
>     > at
>     
> http://docs.sqlalchemy.org/en/latest/orm/relationship_persistence.html#rows-that-point-to-themselves-mutually-dependent-rows
>     
> <http://docs.sqlalchemy.org/en/latest/orm/relationship_persistence.html#rows-that-point-to-themselves-mutually-dependent-rows>,
> 
>     > with a few changes.
>     >
>     > I am trying to handle a situation very similar to the one in that
>     > example, with 2 classes having the same relationship types as
>     those in
>     > the example. However, I would like to create the instances without
>     using
>     > the relationships, and instead populate the fk values directly. The
>     > example uses this, and it works.
>     >
>     > w1 = Widget(name='somewidget')
>     > e1 = Entry(name='someentry')
>     > w1.favorite_entry = e1
>     > w1.entries = [e1]
>     > session.add_all([w1, e1])
>     > session.commit()
>     >
>     > I would like to do this:
>     >
>     > w1 = Widget(widget_id=1, favorite_entry_id=1, name='somewidget')
>     > e1 = Entry(entry_id=1, widget_id=1, name='someentry')
>     > session.add_all([w1, e1])
>     > session.commit()
>     >
>     > The reason I am doing it this way is because I am operating from a
>     JSON
>     > fixture file, and trying to populate a database for unit testing. The
>     > method used in the example works perfectly, but trying to do it my
>     way
>     > yields:
>     >
>     > sqlalchemy.exc.IntegrityError: (IntegrityError) (1452, 'Cannot add or
>     > update a child row: a foreign key constraint fails (`test`.`widget`,
>     > CONSTRAINT `fk_favorite_entry` FOREIGN KEY (`favorite_entry_id`)
>     > REFERENCES `entry` (`entry_id`))') 'INSERT INTO widget (widget_id,
>     > favorite_entry_id, name) VALUES (%s, %s, %s)' (1, 1, 'somewidget')
>     >
>     > I understand the post_update option is on the relationship, and
>     not the
>     > column, so it has no effect on column population. Is there an
>     > alternative method to have that column populated separately via a
>     second
>     > statement, similar to the post_update functionality?
> 
>     Sure, you have to do it manually:
> 
>     w1 = Widget(widget_id=1, favorite_entry_id=None, name='somewidget')
>     e1 = Entry(entry_id=1, widget_id=1, name='someentry')
>     session.add_all([w1, e1])
>     session.flush()  # optional if you're on autoflush
>     session.query(Widget).filter_by(widget_id=1).update(favorite_entry_id=1)
> 
>     session.commit()
> 
> 
> 
> 
> 
> 
> 
>     >
>     > --
>     > You received this message because you are subscribed to the Google
>     > Groups "sqlalchemy" group.
>     > To unsubscribe from this group and stop receiving emails from it,
>     send
>     > an email to sqlalchemy+...@googlegroups.com <javascript:>
>     > <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:>>.
>     > To post to this group, send email to sqlal...@googlegroups.com
>     <javascript:>
>     > <mailto:sqlal...@googlegroups.com <javascript:>>.
>     > Visit this group at http://groups.google.com/group/sqlalchemy
>     <http://groups.google.com/group/sqlalchemy>.
>     > For more options, visit https://groups.google.com/d/optout
>     <https://groups.google.com/d/optout>.
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to sqlalchemy+unsubscr...@googlegroups.com
> <mailto:sqlalchemy+unsubscr...@googlegroups.com>.
> To post to this group, send email to sqlalchemy@googlegroups.com
> <mailto:sqlalchemy@googlegroups.com>.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

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

Reply via email to