简体   繁体   English

编辑外键引用的值时出现 Django IntegrityError

[英]Django IntegrityError when editing a value referenced by a foreign key

I have an app with two (relevant) models, in what is essentially a CRM:我有一个包含两个(相关)模型的应用程序,本质上是一个 CRM:

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"
    )
   ...

Now someone has misspelled a pupil's name and would like to change it pupil_name in StudentTutorRelationshipProfile but because there are already TimeSheet records with the Students misspelled name, Django raises an error (from psychog):现在有人拼错了一个学生的名字,想在pupil_name中更改它的 student_name,但是因为已经有 TimeSheet 记录的学生名字拼错了, StudentTutorRelationshipProfile引发了一个错误(来自psychog):

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".

What is a nice way of changing this data?更改此数据的好方法是什么? I don't mind changing the historic timesheets too or leaving them as is (but can't delete them), what ever is easier / less likley to lead to problems.我也不介意更改历史时间表或将它们保留原样(但不能删除它们),这更容易/不太可能导致问题。 (And yes the fact that I rely on unique name and surname combinations is not ideal, but won't fix that for now unless the change for the IntegrityError also requires some migrations. (是的,我依赖唯一的姓名和姓氏组合这一事实并不理想,但目前不会解决这个问题,除非 IntegrityError 的更改也需要一些迁移。

I'm running python 3.6, Django 3.0 if that helps.如果有帮助,我正在运行 python 3.6、Django 3.0。

This is a good example of why you never want to use a column that might be updated as a foreign key.这是一个很好的例子,说明了为什么您永远不想使用可能被更新为外键的列。 Other bad foreign key candidates are, for example, data that should not be made public, personal or private data like name or social security number, etc. Also, names are not unique, which automatically disqualifies them from being a unique identifier like a primary key.其他不良外键候选者是,例如,不应公开的数据、个人或私人数据(如姓名或社会保险号等)。此外,名称不是唯一的,这会自动取消它们作为主标识符等唯一标识符的资格钥匙。

It is much simpler and safer to use a SERIAL primary key, or sometimes an UUID or other kind of generic, auto-generated identifier that has no other meaning than to identify the row.使用 SERIAL 主键或有时使用 UUID 或其他类型的通用、自动生成的标识符更简单、更安全,除了标识行之外没有其他意义。 It especially should not contain non-ASCII characters, (which also disqualifies names) because you never know if you might have to pipe it through a system that won't handle it, like a human who doesn't speak the language in question ("hello, my login is 指鹿為馬").它尤其不应包含非 ASCII 字符(这也使名称不合格),因为您永远不知道是否可能必须通过无法处理它的系统对其进行 pipe 处理,就像不会说相关语言的人一样( “你好,我的登录名是指鹿为马”)。

In your case, you could have declared your foreign key with ON UPDATE CASCADE, so that updates on the referenced table cascade to the referencing tables.在您的情况下,您可以使用 ON UPDATE CASCADE 声明您的外键,以便引用表上的更新级联到引用表。 This only takes away some of the annoyance, as a simple update of one row may then cause lots of updates in referencing tables.这只会消除一些烦恼,因为对一行的简单更新可能会导致引用表中的大量更新。

You could also update all referencing tables manually, but there will be a time window during which the references will be inconsistent.您也可以手动更新所有引用表,但有时 window 期间引用将不一致。 Setting foreign key constraints to DEFERRED and doing all the updates in a single transaction will probably work.将外键约束设置为 DEFERRED 并在单个事务中进行所有更新可能会起作用。

However this will not update the identifiers in stuff that is outside the database.但是,这不会更新数据库外部内容中的标识符。 For example if the system stores a photo of the pupils with a filename based on the primary key, or writes logs, prints paper, or stores anything anywhere that uses the primary key as a reference... Or if the primary key is used as an identifier in a url, and other websites link to yours using this identifier in the link... then none of that will be updated, or even can be updated.例如,如果系统使用基于主键的文件名存储学生的照片,或者写入日志、打印纸或存储任何使用主键作为参考的任何地方......或者如果主键用作url 中的标识符,以及其他网站使用链接中的此标识符链接到您的标识符......然后这些都不会更新,甚至可以更新。

So yeah, updating or reusing primary keys is a huge can of worms, for absolutely no benefit.所以,是的,更新或重用主键是一大堆蠕虫,绝对没有任何好处。

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

相关问题 Django 使用有效的外键抛出外键 IntegrityError - Django throws a Foreign Key IntegrityError with a valid ForeignKey Django 2.1.7,IntegrityError,FOREIGN KEY约束失败 - Django 2.1.7, IntegrityError, FOREIGN KEY constraint failed Django 3.0.3 IntegrityError FOREIGN KEY 约束在更改数据库时失败 - Django 3.0.3 IntegrityError FOREIGN KEY constraint failed when making changes to db django.db.utils.IntegrityError: FOREIGN KEY 约束在 django 中失败 - django.db.utils.IntegrityError: FOREIGN KEY constraint failed in django 使用 web2py 将 null 值添加到外键时出现 IntegrityError - IntegrityError when adding null value to foreign key using web2py django.db.utils.IntegrityError: FOREIGN KEY 约束失败 - django.db.utils.IntegrityError: FOREIGN KEY constraint failed Django 2.0:sqlite IntegrityError:外键约束失败 - Django 2.0: sqlite IntegrityError: FOREIGN KEY constraint failed 从Django中的外键引用模型访问外键值 - Accessing Foreign Key values from a foreign key referenced model in django 表未监听其他表中外键设置的值,IntegrityError: (sqlite3.IntegrityError) NOT NULL 约束失败 - Table not listening to value set for foreign key in other table, IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed 添加/编辑Django通用外键对象 - adding / editing django generic foreign key objects
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM