我在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自定义“保存”和“删除”方法,检查其他学生是否引用了他们的StudyGroup,然后删除未引用的StudyGroup来完成。也许通过使用信号更优雅。但这似乎应该有一种更简单的方法来实现–像on_delete=models.CASCADE
的反函数。
是否可以告诉数据库自动执行此操作?还是我需要编写自定义代码?
答案 0 :(得分:1)
您可以使用以下查询来删除StudyGroup
不再引用的Student
对象:
StudyGroup.objects.filter(students__isnull=True).delete()
(鉴于您related_name=
parameter [Django-doc]的ForeignKey
[Django-doc]设置为'students'
,因为这是相反关系的名称。)
取决于数据库后端,您可以实现可以执行某些操作的 trigger ,例如,当您删除/更新Student
记录时。但这是特定于后端的。
我们可以向Student
模型添加触发器,以在删除或保存StudyGroup
s时删除没有Student
的{{1}} s:
Student
您将需要在应用程序配置中导入# app/signals.py
from app.models import Student
from django.db.models.signals import post_delete, post_save
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
但是有一些方法可以通过ORM绕过Django信号。例如,使用QuerySet.update
[Django-doc]。
因此,定期运行该方法可能很有用,例如每天/每小时。我们可以使用celery
for that [realpython]或django-periodically
[GitHub]。
话虽如此,但实际上删除# app/app.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
# ...
def ready(self):
import app.signals
并不是最必要的。例如,如果您想检索至少有一个学生的StudyGroup
个中的QuerySet
个,我们可以这样写:
StudyGroup
因此,您可能决定不显示这些# StudyGroups with at least one Student
StudyGroup.objects.filter(student__isnull=False).distinct()
,而不是像soft delete [wiktionary]那样{em}删除StudyGroup
。然后您仍然可以稍后恢复数据,这当然取决于用例。
注意:
StudyGroup
的{{1}}是反向关系的名称,因此related_name
的属性名称用于检索ForeignKey
个中的StudyGroup
个。因此,命名此QuerySet
有点“ 很奇怪”。如果有两个或多个指向同名的Student
的{{1}},则很容易导致冲突。