On 09/15/2010 05:04 PM, BenH wrote:
> Hi,
>
> I'm using SqlAlchemy 0.6.3 and PostgreSQL 8.4 and I'm trying to setup
> a cascading delete between several levels of tables. The problem seems
> to be that I can't have a relationship with cascade="all" and a column
> with ForeignKey that has nullable=False.
>   

Your "cascade" clause is on the wrong side of the relationship. It means
you want to cascade TO the remote object, not FROM the remote object.

> Here is my example:
>
> from sqlalchemy import create_engine, Table, Column, Integer, String,
> MetaData, ForeignKey
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.orm import scoped_session, sessionmaker, relationship
>
> engine = create_engine('postgresql://tsq:passt%qw...@localhost:5432/
> ce_cascade_test', echo=True)
>
> Session = scoped_session(sessionmaker())
> Base = declarative_base()
>
> Session.configure(bind=engine)
>
> s = Session()
>
> class User(Base):
>     __tablename__ = "users"
>
>     id = Column(Integer, primary_key=True)
>     name = Column(String)
>
>     device = relationship("Device", uselist=False)
>   

This should be:

device = relationship("Device", cascade="all", passive_deletes=True, 
uselist=False)

Also, including "uselist=False" indicates that the User-Device
relationship is one-to-one. The lack of a unique constraint on
"devices.user_id" suggests a one-to-many relationship.

>     @classmethod
>     def create(cls, user_name, device_name, manufacturer):
>         new_user = User()
>         new_user.name = user_name
>
>         new_user.device = Device.create(device_name)
>
>         return new_user
>
> class Device(Base):
>     __tablename__ = "devices"
>
>     id = Column(Integer, primary_key=True)
>     name = Column(String)
>     user_id = Column(Integer,
>                      ForeignKey('users.id'),
>                      nullable=False)
>
>     manufacturer_id = Column(Integer,
>                              ForeignKey('manufacturers.id'),
>                              nullable=False)
>
>     user = relationship("User",
>                         uselist=False,
>                         cascade="all")
>   

This should be:

user = relationship("User")

Adding "uselist=False" here is redundant, since that is the default for
the side which contains the foreign key. Also, by including
'cascade="all"', you are telling SQLAlchemy to implicitly delete the
user when the device is deleted. This is probably not what you want.

>     @classmethod
>     def create(cls, name):
>         new_device = Device()
>         new_device.name = name
>
>         return new_device
>
>
> Base.metadata.create_all(engine)
>
> user = User.create("bob", "iphone")
>
> s.add(user)
> s.commit()
>
> s.delete(user)
> s.commit()
>
> If I run this then I get an Integrity error during the delete (because
> it is updating the user_id to null before deleting it). I would like
> to keep the nullable=False on the ForeignKey.
>
> I've tried adding ondelete="CASCADE" to the ForeignKey and adding
> passive_deletes=True to the relationship but it always throw the same
> Integrity error.
>
> I know I'm missing something but I can't find it in the docs, what am
> I missing?
>
> Thanks for your help,
>
> BEN
>   

-Conor

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to