Thank you both for the advice. Dern NULLs causing trouble again. GL
On Tue, Sep 15, 2009 at 4:34 PM, Conor <conor.edward.da...@gmail.com> wrote: > > On Sep 15, 4:08 pm, "Michael Bayer" <mike...@zzzcomputing.com> wrote: > > Gregg Lind wrote: > > > What I think I'm seeing is that an object can be created even without > it's > > > ForeignKeyConstraint being filled. > > > > > To run the test code below: > > > > > $ dropdb test18; createdb test18; python testcode.py > > > > "on" is not defined: > > > > ForeignKeyConstraint(['regstring_id', 'regstring','regstring_type'], > > [A1String.id, A1String.string, A1String.origin], on), > > > > when removing "on", the row inserts with "regstring_id" as NULL. PG > > appears to accept this so I would assume PG considers a three-column > > foreign key with one NULL to be NULL. If I try it with all three columns > > not null, then you get the constraint error. > > > > SQLalchemy itself relies upon the database to enforce constraints. In > > this case you should have the "NOT NULL" constraint on the Product > > columns. > > > > To expand on this: > Most (all?) databases default to a MATCH SIMPLE policy for foreign key > constraints: if any FK column is NULL then the FK constraint is > satisfied (regardless of the actual values of the non-null columns). > It looks like you want MATCH FULL behavior: if some but not all FK > columns are NULL then the FK constraint fails. > > Assuming you really do need the the FK columns to be nullable, you > have to either add MATCH FULL to your DDL (probably have to use DDL() > + ALTER TABLE; also requires that your database actually supports > MATCH FULL) or add a check constraint that mimics the MATCH FULL > behavior, e.g.: > (regstring_id IS NULL) = (regstring IS NULL) = (regstring_type IS > NULL) > > > > This builds on > > >http://groups.google.com/group/sqlalchemy/browse_thread/thread/eb240f. > .. > > > . > > > > > I understand that the foreign table can't create the referent. (and > > > finding > > > the best idiom for "use one if it exists or create one") is yet be > > > determined. What I truly don't understand is how any instances of > > > "Product" > > > can be created, since there is a FK constraint that is not fulfulled. > > > > > 1. Is the foreign key constraint fulfilled? > > > 2. Is there a good "create the referent if it doesn't exist, else use > it" > > > idiom? > > > 3. Is the polymorphic table business complicating it? It seems liek > the > > > compound primary key for A1String is. > > > > > ---------------- > > > from sqlalchemy.ext.declarative import > > > declarative_base > > > from sqlalchemy import CheckConstraint, ForeignKey, MetaData, > > > PrimaryKeyConstraint > > > from sqlalchemy import ForeignKeyConstraint > > > from sqlalchemy import Table, Column, Integer, Boolean,Unicode,String > > > from sqlalchemy.orm import relation, backref > > > from sqlalchemy import create_engine > > > from sqlalchemy.orm import sessionmaker > > > from sqlalchemy.schema import DDL > > > > > import sys > > > ECHO = bool((sys.argv + [False])[1]) > > > > > ## utilties for connecting the db, printing it, etc. > > > def print_schema(T="postgres", Base=None): > > > ''' print print_schema will print the schema in use ''' > > > from StringIO import StringIO > > > buf = StringIO() > > > engine = create_engine('%s://' % T, strategy='mock', > executor=lambda > > > s, > > > p='': buf.write(str(s) + p)) > > > Base.metadata.create_all(engine) > > > return buf.getvalue() > > > > > def db_setup(connstring='sqlite:///:memory:', echo=False, Base=None): > > > engine = create_engine(connstring, echo=echo) > > > Session = sessionmaker(bind=engine, autoflush=False, > autocommit=False) > > > session = Session() > > > Base.metadata.bind = engine > > > Base.metadata.create_all() > > > return session, engine > > > > > def _class_repr(self): > > > ''' print our SA class instances in a nicer way ''' > > > # ugly, use sparingly, may have performance hit > > > d = [(k,v) for k,v in self.__dict__.iteritems() if k[0] != "_"] > > > d = sorted(d, key=lambda x: x[0].lower()) > > > return "<%s, %s>" % (self.__class__, d) > > > > > Base = declarative_base() > > > > > class Polystring(Base): > > > __tablename__ = 'strings' > > > id = Column(Integer, nullable=False, primary_key=True) > > > string = Column(String, nullable=False, primary_key=True) > > > origin = Column(String, nullable=False, primary_key=True) > > > __mapper_args__ = {'polymorphic_on': origin} > > > > > # subtype of string > > > class A1String(Polystring): > > > __mapper_args__ = {'polymorphic_identity': 'a1'} > > > products = relation('Product', order_by="Product.id") > > > > > class Product(Base): > > > __tablename__ = 'product' > > > __table_args__ = ( > > > ForeignKeyConstraint(['regstring_id', 'regstring', > > > 'regstring_type'], [A1String.id, A1String.string > > > , A1String.origin], on), > > > {} > > > ) > > > id = Column(Integer,primary_key=True) > > > regstring_id = Column(Integer) > > > regstring = Column(String) > > > regstring_type = Column(String,default="asn") > > > > > ## test code > > > session,eng = db_setup("postgres:///test18", Base=Base, echo=ECHO) > > > add = session.add > > > q = session.query > > > c = session.commit > > > r = _class_repr > > > > > A = Product(id=192832, regstring="some part id") > > > print r(A) > > > add(A) > > > c() # commit > > > print map(r,q(Product).all()) > > > print "somehow this managed to get in, without making a polystring, > which > > > it > > > should be referencing." > > > assert len(q(Polystring).all()) > 0, "So, where is the polystring?" > > > ---------- > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---