简体   繁体   中英

SqlAlchemy foreign key constraint

I'm having a problem understanding how a ForeignKey constraint works with SqlAlchemy when I'm inserting new records. I've got a parent table that has two child tables, each is a one_2_many relationship. My underlying DB is Oracle, and here's a simplified model of my tables:

class ProductCategory(db.Model):
  __tablename__ = 'productcategory'
  product_category_id = Column(Integer, Sequence('productcategory_seq', primary_key=True)
  label = Column(String)
  products = relation('Product', backref='product_category')
  printers = relation('Printer', backref='product_category')

class Product(db.Model):
  __tablename__ = 'product'
  product_id = Column(Integer, Sequence('product_seq'), primary_key=True)
  product_category_id = Column(Integer, ForeignKey('productcategory.product_category_id')
  name = Column(String)

class Printer(db.Model):
  __tablename__ = 'printer'
  printer_id = Column(Integer, Sequence('printer_seq'),
  product_category_id = Column(Integer, ForeignKey('product_category.product_category_id')
  name = Column(String)

And here's a simplified example of the Python code that's raising a (cx_Oracle.IntegrityError) ORA-02291: integrity constraint (EASTLAB.SYS_C0049050) violated - parent key not found exception

try:
  product_category = ProductCategory(label='some_category')
  db.session.add(product_category)

  # iterate over the products in the category
  for product in products:
    new_product = Product(
      product_category=product_category,
      name=product.name
    )
    db.session.add(new_product)

  # iterate over the printers in the category
  for printer in printers:
    new_printer = Printer(
      product_category=product_category,
      name=printer.name
    )
    db.session.add(new_printer)

  # commit before exiting context manager
  db.session.commit()
except:
  db.session.rollback()

The exception is raised at the point where the db.session.commit() code is executed. I'm not sure why the exception is being raised, what I'm doing above seems to be a pattern I've seen in various online postings. The interesting thing is if I comment out the code that adds the printer children, this works fine. I'm very confused... :)

Any help, pointers or suggestions would be greatly appreciated!

Thanks in advance, Doug

The foreign key product_category_id on Printer is referencing 'product_category.product_category_id' and not 'productcategory.product_category_id' .

Tested this with the below which works for me:

class ProductCategory(Base):
    __tablename__ = 'productcategory'
    product_category_id = Column(Integer, Sequence('productcategory_seq'), primary_key=True)
    label = Column(String)
    products = relation('Product', backref='product_category')
    printers = relation('Printer', backref='product_category')


class Product(Base):
    __tablename__ = 'product'
    product_id = Column(Integer, Sequence('product_seq'), primary_key=True)
    product_category_id = Column(Integer, ForeignKey('productcategory.product_category_id'))
    name = Column(String)


class Printer(Base):
    __tablename__ = 'printer'
    printer_id = Column(Integer, Sequence('printer_seq'), primary_key=True)
    product_category_id = Column(Integer, ForeignKey('productcategory.product_category_id'))
    name = Column(String)


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

product_category = ProductCategory(label='some_category')
session.add(product_category)

product_names = ["a", "b", "c"]

# iterate over the products in the category
for product in product_names:
    new_product = Product(
        product_category=product_category,
        name=product
    )
    session.add(new_product)

printer_names = ["a", "b", "c"]

# iterate over the printers in the category
for printer in printer_names:
    new_printer = Printer(
        product_category=product_category,
        name=printer
    )
    session.add(new_printer)

# commit before exiting context manager
session.commit()

Slightly different from your example as you left out some closing brackets when you added the example to your question and I slightly changed how it got the samples for Printers and Products .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM