SQLAlchemy, добавление записей с зависимостью от ограничений внешнего ключа

#python #postgresql #sqlalchemy #flask-sqlalchemy #circular-dependency

#python #postgresql #sqlalchemy #flask-sqlalchemy #циклическая зависимость

Вопрос:

Я новичок в Flask-SQLAchemy и SQLAlchemy, пытаюсь понять ограничения и взаимосвязи, поэтому я написал приведенный ниже код из хорошо известного примера базы данных. Каждый экземпляр Employee принадлежит отделу, и у каждого экземпляра отдела есть сотрудник в качестве менеджера. Оба внешних ключа, dnumber и mgrssn, не могут быть нулевыми. Код работает так, как ожидалось, и создает точно такую же схему, созданную кодом SQL.

 from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql psycopg2://postgres:<password>@<host>:<port>/<dbname>'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)


class Employee(db.Model):
    __tablename__ = 'employee'
    __table_args__ = ({"schema": "public"})
    ssn = db.Column('ssn', db.String(11), primary_key=True)
    fname = db.Column('fname', db.String(20), nullable=False)
    lname = db.Column('lname', db.String(20), nullable=False)
    bdate = db.Column('bdate', db.Date, nullable=False)
    address = db.Column('address', db.String(50), nullable=False)
    sex = db.Column('sex', db.String(1), nullable=False)
    salary = db.Column('salary', db.Integer, nullable=False)

    # Relationship (1-1): Employee --has-> Employee (as supervisor)
    superssn = db.Column('superssn',
                         db.String(11),
                         db.ForeignKey('public.employee.ssn', name='supervisor'))
    emp_supervisor = db.relationship('Employee', backref=db.backref(name='supervisor', remote_side=ssn), lazy='dynamic')

    # Relationship (1-M): Department --has-> Employee(s)
    dnumber = db.Column('dnumber',
                        db.Integer,
                        db.ForeignKey("public.department.dnumber", name='department'),
                        nullable=False)

    # Relationship (1-M): Employee(manager) --manages-> Department(s)
    dep_manager = db.relationship('Department', backref='manager', lazy='dynamic', foreign_keys="[Department.mgrssn]", post_update=True)


class Department(db.Model):
    __tablename__ = "department"
    __table_args__ = ({"schema": "public"})
    dnumber = db.Column('dnumber', db.Integer, primary_key=True)
    dname = db.Column('dname', db.String(50), unique=True, nullable=False)

    # Relationship (1-M): Employee(manager) --manages-> Department(s)
    mgrssn = db.Column('mgrssn',
                       db.String(11),
                       db.ForeignKey("public.employee.ssn", name='manager'),
                       nullable=False,
                       unique=True)

    mgrstartdate = db.Column('mgrstartdate', db.Date, nullable=False)

    # Relationship (1-M): Department --has-> Employee(s)
    employees = db.relationship('Employee', backref='department', lazy='dynamic', foreign_keys="[Employee.dnumber]", post_update=True)

    def __repr__(self):
        return f'<Department> {self.dname}'
  

Проблема начинается, когда я пытаюсь вставить строки, в то время как я не могу найти правильный порядок создания и обновления экземпляров с учетом ограничений. Я провел несколько тестов, таких как приведенный ниже, который возвращает очевидную ошибку:
«ошибка sqlalchemy.exc.IntegrityError: (psycopg2.errors.NotNullViolation) нулевое значение в столбце «dnumber» нарушает ненулевое ограничение ПОДРОБНО: ошибка строки содержит (888-66-5555, Джеймс Э., Борг, 1937-11-10, 450 Стоун,. Хьюстон, Техас, Массачусетс, 55000, 888-66-5555, null).«

 if __name__ == "__main__":

    db.create_all()

    emp1 = Employee(ssn='888-66-5555', fname='James E', lname='Borg', bdate='1937-11-10', address='450 Stone,. Houston, TX', sex='M', salary=55000, superssn='888-66-5555')
    dep1 = Department(dnumber=5, dname='Research', mgrstartdate='1998-05-22')
    emp1.department = dep1
    db.session.add(emp1)
    dep1.manager = emp1
    db.session.add(dep1)
    db.session.commit()
  

Используя синтаксис SQL с WITH xxx AS INSERT помощью I, я могу управлять порядком инструкций insert. Однако я не могу найти, как добиться этого в SQLAlchemy, когда внешние ключи существуют в обеих связанных таблицах?