Django:如何删除不再引用的任何外键对象

标签 django foreign-keys

我在我的 Django Rest Framework 应用程序中嵌套了数据,如下所示:

class Student(models.Model):
    studyGroup = models.ForeignKey(StudyGroup, on_delete=models.SET_NULL,  blank=True, null=True, related_name='student')

每个学生都可以有一个学习小组;学生可能没有学习小组。

许多学生可以有同一个学习小组。

我想自动删除任何未被任何学生引用的 StudyGroup,无论是因为学生被删除还是因为它已更新。

我认为这可以通过为 Student 自定义 'save' 和 'delete' 方法来完成,检查他们的 StudyGroup 是否被任何其他 Student 引用,如果没有被引用则删除它。或者更优雅地使用信号。但感觉应该有一种更简单的方法来做到这一点 - 就像 on_delete=models.CASCADE 的逆运算。

有没有办法告诉数据库自动执行此操作?还是我需要编写自定义代码?

最佳答案

您可以使用以下查询删除不再被 Student 引用的 StudyGroup 对象:

StudyGroup.objects.<b>filter(students__isnull=True).delete()</b>

(鉴于您的 related_name= parameter [Django-doc]ForeignKey [Django-doc] 设置为 'students',因为这是反向关系的名称)。

根据数据库后端,您可以实现一个可以执行特定操作的触发器,例如,当您删除/更新Student 记录时。但这是特定于后端的。

我们可以在Student模型中添加一个触发器,在删除或保存Student时移除没有StudentStudyGroup :

# app/signals.py

from app.models import Student
from django.db.models.signals import <b>post_delete, post_save</b>
from django.dispatch import receiver

@receiver([post_delete, post_save], sender=Student)
def update_delete_student(sender, instance, **kwargs):
    StudyGroup.objects.filter(students__isnull=True).delete()

您需要在您的应用程序配置中导入 signals 模块:

# app/app.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):

    # ...

    def ready(self):
        import app.signals

但是有一些方法可以通过 ORM 绕过 Django 信号。例如使用 QuerySet.update [Django-doc] .

因此,定期运行该方法可能很有用,例如每天/每小时。我们可以使用 celery for that [realpython]django-periodically [GitHub] .

话虽这么说,但删除 StudyGroup 本身可能并不是最有必要的。例如,如果您想要检索至少有一个学生的 StudyGroupQuerySet,我们可以这样写:

# StudyGroups with at least one Student
StudyGroup.objects.filter(<b>student__isnull=False</b>)<b>.distinct()</b>

因此,您可能决定不显示这些 StudyGroup,而不是删除 StudyGroup,例如 soft delete [wiktionary] .然后您仍然可以稍后恢复数据,这当然取决于用例。

Note: the related_name of a ForeignKey is the name of the relation in reverse, so the name of the attribute of a StudyGroup to retrieve the QuerySet of Students. Therefore naming this 'studyGroup' is a bit "weird". It would also easily result in collisions if there are two or more ForeignKeys that point to StudyGroup with the same name.

关于Django:如何删除不再引用的任何外键对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56314944/

相关文章:

python - 如何对 Django 模型对象的字母数字列表进行排序

python - data 必须类似于 QuerySet(具有 count() 和 order_by())或支持 list(data) —— NoneType 两者都不具备

django - 将 {% url %} 传递给 Django 中的自定义模板标签

MYSQL多表选择查询

Mysqldump 和表的顺序

mysql - 外键识别关系和非识别关系之间的性能差异

django - 如何查看Django ORM的查询集对应的SQL查询?

Django 序列化程序 : What does is_valid actually do?

mysql - 作为多个复合 FK 约束一部分的一列是否有效且良好的设计决策?

mysql - 为什么我不能以这种方式添加外键约束?