Каскадное удаление с sqlalchemy в питоне - PullRequest
0 голосов
/ 20 апреля 2019

У меня есть две таблицы в моей базе данных план и план_руль. План содержит несколько правил

Я создал свою таблицу plan_rule следующим образом, поэтому она имеет каскадное удаление для записей, у которых в строке нет plan_id

CREATE TABLE [dbo].[plan_rule](
    [created_by] [VARCHAR](25) NULL,
    [created_datetime] [DATETIME] NULL,
    [modified_by] [VARCHAR](25) NULL,
    [modified_datetime] [DATETIME] NULL,
    [active] [BIT] NULL,
    [id] [INT] IDENTITY(1,1) NOT NULL,
    [plan_id] [INT] NOT NULL,
    [rule_data] [INT] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[plan_rule]  WITH CHECK ADD  CONSTRAINT [CK_plan_rule_Cascade] FOREIGN KEY([plan_id])
REFERENCES [dbo].[plan] ([id])
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[plan_rule] CHECK CONSTRAINT [CK_plan_rule_Cascade]
GO

В питоне я определил мои отношения следующим образом

class Plan(Base):
    __tablename__ = 'plan'
    id = Column(Integer, Sequence('plan_id_seq'), primary_key=True)
    plan_name = Column(Unicode(255), nullable=False)

    plan_rules = relationship(
        "PlanRule",
        # uselist=False,
        backref="plan"
    )   

    def __init__(self, request=None, params=None):
        self.initialize(request=request, params=params)

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

Я пытаюсь сделать это следующим образом

def save_rules(request, params, rec_id, plan):
    rules = find_rule_params(params, plan.id)
    if rec_id: #there is an update to the plan
        plan.plan_rules = [] #clear old rules
    for rule in rules:
        try:
            rec = PlanRule(request=request, params=rule)
        except Exception as e:
            # If there are errors adding, abort
            LOG.exception('Encountered error during plan creation:')
            transaction.abort()
            resp = {
                'status': False,
                'message': 'Unable to add a record due to database constraints.'
            }
            return resp
        # If there are errors adding, abort
        if rec.errors:
            transaction.abort()
            resp = {'status': False, 'errors': rec.errors}
            LOG.debug('Encountered errors while adding a plan: {}'.format(resp))
            return resp
        # Success! Set modification fields
        rec.modified_by = rec.created_by = request.remote_user
        # Load relationships before dictifying
        rec.load_relationships()
        plan.plan_rules.append(rec) #add the new record
    return plan

Следующий код хорошо работает для новых правил, но когда я пытаюсь выполнить обновление, я получаю следующую ошибку

Обнаружена ошибка при создании плана:

Traceback (most recent call last):
    rec = PlanRule(request=request, params=rule)


IntegrityError: (pymssql.IntegrityError) (515, "Cannot insert the value NULL into column 'plan_id', table 'plan_rule'; column does not allow nulls. UPDATE fails.DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n") [SQL: 'UPDATE plan_rule SET plan_id=%(plan_id)s WHERE plan_rule.id = %(plan_rule_id)s'] [parameters: ({'plan_id': None, 'plan_rule_id': 1}, {'plan_id': None, 'plan_rule_id': 2}, {'plan_id': None, 'plan_rule_id': 3})] (Background on this error at: http://sqlalche.me/e/gkpj)

Я предполагаю, что это как-то связано с тем, как я удаляю старые строки из таблицы, но я не уверен, почему это не работает.

...