Django 模型外键 on_delete=null 但外键还是被删除了
Posted
技术标签:
【中文标题】Django 模型外键 on_delete=null 但外键还是被删除了【英文标题】:Django model foreign key on_delete=null but foreign key is deleted anyway 【发布时间】:2020-06-18 12:20:55 【问题描述】:我正在尝试将删除时的外键引用从级联更改为 null,如下所示:
created_by = models.ForeignKey(CustomUser,on_delete=models.SET_NULL, null=True)
当我通过从 CustomUser 中删除记录来测试这一点时,我会在执行删除之前和之后获得 Games 表中对象的计数。
p = Games.objects.count()
print(p) #outputs 100
print(Games.objects.filter(created_by=2)) #outputs <QuerySet [<Games: 181 79 None>]>
cu = CustomUser.objects.get(pk=2)
cu.delete()
p = Games.objects.count()
print(p) #outputs 98
print(Games.objects.filter(created_by=2)) # outputs <QuerySet []>
我尝试使用其他值进行删除,但唯一不从数据库中删除行的值是保护。相反,它会引发保护错误
raise ProtectedError(
django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'CustomUser' because they are referenced through a protected foreign key: 'Games.created_by'", <QuerySet [<Games: 181 79 None>]>)
CustomUser 和 Games 模型的代码
class CustomUser(AbstractBaseUser, PermissionsMixin):
id = models.BigAutoField(primary_key=True)
username = models.CharField(max_length=15, unique=True)
email = models.EmailField(max_length=128, unique=True)
password = models.CharField(max_length=254)
salt = models.CharField(max_length=128)
email_verified = models.BooleanField(default=False)
avatar = models.ImageField(blank=True, null=True)
date_joined = models.DateTimeField(default=timezone.now)
last_updated = models.DateTimeField(blank=True, null=True)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
objects = CustomUserManager()
def __str__(self):
return self.email
class Games(models.Model):
CATEGORY = (
('general knowledge','general knowledge'),
('science','science'),
('mythology','mythology'),
('sports','sports'),
('geography','geography'),
('history','history'),
('politics','politics'),
('art','art'),
('celebrities','celebrities'),
('animals','animals'),
('vehicles','vehicles'),
('entertainment','entertainment'),
('random','random')
)
id = models.BigAutoField(primary_key=True)
number_of_questions = models.SmallIntegerField()
number_of_players = models.SmallIntegerField()
start_time = models.DateTimeField(default=timezone.now)
category = models.CharField(max_length=18, choices=CATEGORY)
created_by = models.ForeignKey(CustomUser,on_delete=models.SET_NULL, null=True)
result_id = models.ForeignKey(Results, on_delete=models.CASCADE, null=True, blank=True)
sudden_death_id = models.ForeignKey(SuddenDeath, on_delete=models.CASCADE, null=True, blank=True)
objects = models.Manager()
def __str__(self):
return '%s %s %s' % (self.id, self.result_id, self.sudden_death_id)
【问题讨论】:
你的 Django 版本是多少? @LucasWieloch 3.0.7models.SET_NULL
的外键参数是正确的。您确定您的迁移是最新的吗?
@LucasWieloch 是的,我只是仔细检查了一下,我的迁移是最新的
好吧,我会提示您在删除之前通过将游戏 pks 连接到cu
来测试它,并在删除后执行Games.objects.filter(pk__in=game_pks)
以确保记录仍然存在。除此之外,我建议您发布一个带有更大代码 sn-p 的示例,因为无论错误是什么,它都可能超出您问题中块的范围
【参考方案1】:
我使用 django-extensions
reset_db
重置了我的数据库,删除了所有迁移并重新运行。 makemigrations
& migrate
从我的灯具中导入相同的数据集后,我再次运行了这段代码
p = Games.objects.count()
print(p) #output 100
print(Games.objects.filter(created_by=2)) # output <QuerySet [<Games: 181 79 None>]>
cu = CustomUser.objects.get(pk=2)
cu.delete()
p = Games.objects.count()
print(p) #output 100
print(Games.objects.get(pk=181)) #output 181 79 None
这确认外键行没有被删除。
我将此标记为已接受的答案,但如果有人能够解释如何在不重置数据库的情况下解决问题,我会将其标记为已接受的答案。
【讨论】:
以上是关于Django 模型外键 on_delete=null 但外键还是被删除了的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的模型的“on_delete=models.CASCADE”不生成级联外键约束?
如何使用 on_delete 属性在用户模型的外键字段中设置用户全名?