Таблица не прослушивает значение, установленное для внешнего ключа в другой таблице, ошибка целостности: (sqlite3.Ошибка целостности) НЕ удалось выполнить ограничение NOT NULL

#python #sqlite #sqlalchemy

#python #sqlite #sqlalchemy

Вопрос:

У меня есть внешний ключ в PropertyChange таблице, который находится id в Run таблице. Когда я запускаю и фиксирую данные для обеих таблиц, я получаю IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: PropertyChange.run_id . Из того, что я прочитал, настройка autoincrement=True в Run таблице должна была решить эту проблему.

models.py

 class Run(Base):
    __tablename__ = 'Run'

    id = Column(Integer, primary_key=True, autoincrement=True)
    instance = Column(Integer, nullable=True)
    name = Column(String, nullable=False)
    host = Column(String, nullable=False)
    config = Column(JSON, nullable=False)

    property_change = relationship('PropertyChange', back_populates='run')


class PropertyChange(Base):
    __tablename__ = 'PropertyChange'

    id = Column(Integer, primary_key=True, autoincrement=True)
    timestamp = Column(DateTime(timezone=True), nullable=False)
    property_name = Column(String, nullable=True)
    p_values = Column(JSON, nullable=False)
    s_values = Column(JSON, nullable=False)
    c_values = Column(JSON, nullable=True)

    run_id = Column(Integer, ForeignKey('Run.id'), nullable=False)
    run = relationship('Run', back_populates='property_change')
 

Добавление и фиксация данных, поскольку мои данные находятся в dataframe:

 prod_run = models.Run
prop_change = models.PropertyChanges
pending_data = []
for row in run_df.itertuples():
    pending_data.append(prod_run(instance =row.instance, name=row.name, host =row.host, config = row.config ))
for row in property_changes.itertuples():
    pending_data.append(prop_change(timestamp=row.timestamp, property_name=row.property_name, p_values=row.p_values, s_values=row.s_values, c_values=row.c_values))
session.add_all(pending_data)
session.commit()
 

Комментарии:

1. Два примечания: (1) По умолчанию SQLite не применяет ограничения внешнего ключа. Подробности здесь . (2) Если у вас уже есть данные в двух отдельных фреймах данных, тогда зачем создавать объекты ORM и добавлять их в сеанс, когда вы можете просто загрузить данные непосредственно в базовые таблицы? Вы всегда можете получить определенные объекты ORM после обновления таблиц.

2. Мой вопрос при загрузке непосредственно из фрейма данных заключается в том, как мне сообщить PropertyChange таблице о run_id Run таблице? Это генерируется после того, как я передаю данные в Run таблицу.

3. Если у вас уже есть данные в двух отдельных фреймах данных, то они уже должны иметь общее значение ключа для связывания строк. Если вы не можете использовать это общее (ключевое) значение в качестве первичного ключа для запуска (например, потому что оно уникально в этом подмножестве строк, но не уникально глобально), то вы могли бы, по крайней мере, использовать его для связывания строк в этом конкретном пакете.

4. Мне все еще нужно сгенерировать глобально уникальный идентификатор … на чем я и застрял с dataframe.to_sql(). Что, я думаю, может сработать, и это супер хакерство — сначала зафиксировать таблицу выполнения, а затем запросить БД и взять идентификатор последней добавленной строки и назначить его в качестве столбца run_id для каждой строки в property_changes dataframe. Затем зафиксируйте эту таблицу, чтобы она имела правильный глобально уникальный идентификатор. Однако это довольно хитрый обходной путь. Есть еще идеи?

5. Я недостаточно знаю о ваших данных, чтобы написать что-то большее, чем комментарий в форме ответа (который технически «не является ответом»). Если вы исправите подход ORM и опубликуете свое решение в качестве ответа (можно ответить на свой собственный вопрос), то, если вы хотите дополнительно изучить параметр DataFrame-to-table (например, если вы обнаружите, что подход ORM медленный, что может оказаться), тогда выможете задать это как отдельный вопрос.

Ответ №1:

Поскольку часть комментария слишком коротка для обсуждения решений, я перейду сюда:

Я упомяну некоторые моменты для проверки и решения:

(1) проверьте данные в ваших фреймах данных, связанных со столбцами nullable=False . есть ли в nan значениях. ( name, host and config в run_df и timestamp, p_values, s_values в PropertyChange )

(2) Переопределение столбца ‘run_id in PropertyChange , you make it nullable=False , and you assigned neither a valid Run.id nor a reference to the object of Тип «Выполнить».

(3) Наконец, вы устанавливаете связь run = relationship('Run', back_populates='property_change') в модели PropertyChange без связанного внешнего ключа в Run модели, я столкнулся с неожиданными проблемами с SQLAlchemy для подобных случаев.

ищу либо решаемые, либо комментарии 🙂