首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >编辑由外键引用的值时的Django IntegrityError

编辑由外键引用的值时的Django IntegrityError
EN

Stack Overflow用户
提问于 2021-02-06 21:31:17
回答 1查看 84关注 0票数 0

我有一个应用程序,有两个(相关的)模型,本质上是一个CRM:

代码语言:javascript
复制
class StudentTutorRelationshipProfile(models.Model):
    pupil_name = models.CharField(max_length=100, unique=True)
    parent_name = models.CharField(max_length=100)
    ...

class TimeSheet(models.Model):
    user = models.ForeignKey(
        User, on_delete=models.PROTECT, limit_choices_to={"is_tutor": True}
    )
    student = models.ForeignKey(
        StudentTutorRelationshipProfile, on_delete=models.CASCADE, to_field="pupil_name"
    )
   ...

现在有人拼错了学生的名字,并想在StudentTutorRelationshipProfile中将其更改为pupil_name,但是因为已经有学生姓名拼写错误的TimeSheet记录,Django引发了一个错误(来自StudentTutorRelationshipProfile):

代码语言:javascript
复制
ForeignKeyViolation: update or delete on table "invoicing_studenttutorrelationshipprofile" violates foreign key constraint "invoicing_timesheet_student_id_07889dc0_fk_invoicing" on table "invoicing_timesheet"
DETAIL:  Key (pupil_name)=(Student Name) is still referenced from table "invoicing_timesheet".

  File "django/db/backends/base/base.py", line 243, in _commit
    return self.connection.commit()

IntegrityError: update or delete on table "invoicing_studenttutorrelationshipprofile" violates foreign key constraint "invoicing_timesheet_student_id_07889dc0_fk_invoicing" on table "invoicing_timesheet"
DETAIL:  Key (pupil_name)=(Student Name) is still referenced from table "invoicing_timesheet".

更改此数据的好方法是什么?我也不介意更改历史时间表,或者让它们保持原样(但不能删除它们),无论哪种方式更容易/不太可能导致问题。(是的,我依赖唯一的名字和姓氏组合的事实并不理想,但目前不会解决这个问题,除非对IntegrityError的更改也需要进行一些迁移。

我运行的是python 3.6,Django 3.0,如果有帮助的话。

EN

回答 1

Stack Overflow用户

发布于 2021-02-06 21:54:43

这是一个很好的例子,说明了为什么您永远不想使用可能被更新为外键的列。其他不好的外键候选是,例如,不应该公开的数据,个人或私有数据,如姓名或社会保险号等。此外,姓名不是唯一的,这自动取消了它们作为唯一标识符的资格,如主键。

使用串行主键要简单得多,也更安全,有时使用UUID或其他类型的通用、自动生成的标识符,除了标识行之外没有其他意义。它尤其不应该包含非ASCII字符(这也会取消名称的限定),因为您永远不知道是否必须通过一个无法处理它的系统来处理它,就像一个不会说有问题的语言的人(“你好,我的登录名是指鹿為馬")。

在您的例子中,您可以使用ON UPDATE CASCADE声明您的外键,这样被引用表上的更新就会级联到引用表。这只会减少一些麻烦,因为对一行的简单更新可能会导致引用表中的大量更新。

您也可以手动更新所有引用表,但会有一段时间窗口,在此期间引用将不一致。将外键约束设置为DEFERRED并在单个事务中完成所有更新可能会起作用。

但是,这不会更新数据库之外的内容中的标识符。例如,如果系统存储具有基于主键的文件名的学生照片,或者写入日志、打印纸张或将任何使用主键作为引用的内容存储在任何地方……或者如果主键被用作url中的标识符,而其他网站在链接中使用此标识符链接到您的网站...那么这些都不会被更新,甚至不能被更新。

所以,更新或重用主键是一个巨大的蠕虫罐头,绝对没有任何好处。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66077437

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档