繁体   English   中英

如何修复 IntegrityError:(psycopg2.errors.ForeignKeyViolation)更新或删除表“用户”违反外键约束

[英]How to fix IntegrityError: (psycopg2.errors.ForeignKeyViolation) update or delete on table "users" violates foreign key constraint

我在下面使用 Flask-SQLAlchemy 创建了两个表 - 它们具有一对一的关系。

class Logo(db.Model):
    __tablename__ = "logo"
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(100))
    data = db.Column(db.LargeBinary)
    username = db.Column(db.String(100), db.ForeignKey("users.username"))

    users = db.relationship("User", backref=backref("logo", uselist=False))

    def __init__(self, filename: str, data, username: str):
        self.filename = filename
        self.data = data
        self.username = username

    def __repr__(self) -> str:
        return "<Logo (filename='{}', username='{}')>".format(
            self.filename, self.username
        )


class User(UserMixin, db.Model):
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), unique=True)
    password = db.Column(
        db.String(200), primary_key=False, unique=False, nullable=False
    )
    is_admin = db.Column(db.Boolean, default=False, nullable=True)

    def __init__(
        self,
        username: str,
        password: str,
        is_admin: bool = False,
    ):
        self.username = username
        self.password = self.set_password(password)
        self.is_admin = is_admin

    def get_id(self):
        return self.username

    def set_password(self, password: str) -> str:
        return generate_password_hash(password, method="sha256")

    def check_password(self, password: str):
        return check_password_hash(self.password, password)

    def __repr__(self) -> str:
        return "<User {}>".format(self.username)

我想在用户想要一个新用户名的情况下更新用户表:

user01 = User.query.filter_by(username="user01").first()
logo = Logo.query.filter_by(username="user01").first()

new_username= "newusertest"
user01.username = new_username
logo.users = user01

logo.username = new_username

db.session.add(user01)
db.session.add(logo)


db.session.commit()

db.session.commit抛出以下错误:

IntegrityError: (psycopg2.errors.ForeignKeyViolation) update or delete on table "users" violates foreign key constraint "logo_username_fkey" on table "logo"
DETAIL:  Key (username)=(user01) is still referenced from table "logo".

[SQL: UPDATE users SET username=%(username)s WHERE users.id = %(users_id)s]
[parameters: {'username': 'newusertest', 'users_id': 2}]
(Background on this error at: https://sqlalche.me/e/14/gkpj)

该错误表示徽标表仍然具有旧用户名,但我已对其进行了更新,但我不知道为什么再次出现,我在过去的 2 个小时中调试并尝试了不同的东西,但没有任何效果。

尝试在用户关系中定义cascade="all,delete"

您可以暂时使外键约束可延迟并在 psql 中进行更新。 假设我们有这些表:

test# \d parent
                              Table "public.parent"
 Column │       Type        │ Collation │ Nullable │           Default            
════════╪═══════════════════╪═══════════╪══════════╪══════════════════════════════
 id     │ integer           │           │ not null │ generated always as identity
 name   │ character varying │           │          │ 
Indexes:
    "parent_name_key" UNIQUE CONSTRAINT, btree (name)
Referenced by:
    TABLE "child" CONSTRAINT "child_pname_fkey" FOREIGN KEY (pname) REFERENCES parent(name)

test# \d child
                               Table "public.child"
 Column │       Type        │ Collation │ Nullable │           Default            
════════╪═══════════════════╪═══════════╪══════════╪══════════════════════════════
 id     │ integer           │           │ not null │ generated always as identity
 pname  │ character varying │           │          │ 
Foreign-key constraints:
    "child_pname_fkey" FOREIGN KEY (pname) REFERENCES parent(name)

那么声明将是

test# alter table child alter constraint child_pname_fkey deferrable;
ALTER TABLE
SET CONSTRAINTS
test# begin;
BEGIN
test#* set constraints child_pname_fkey deferred;
SET CONSTRAINTS
test#* update child set pname = 'Alice' where id = 1;
UPDATE 1
test#* update parent set name = 'Alice' where id = 1;
UPDATE 1
test#* commit;
COMMIT
test# alter table child alter constraint child_pname_fkey not deferrable;
ALTER TABLE
test#

延迟约束意味着更新在事务结束时而不是立即进行评估,因此从数据库的角度来看,列不会不同步。

长期的解决方案是使用users.id作为外键,因为它不太可能改变。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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