遍历抽象Django模型的所有外键相关子类
我正在尝试遍历一个特定的 Django 模型所有相关的外键模型。可能有 13 个不同的模型与之有外键关系,但它们都继承自同一个抽象基类。我想在一个循环中遍历它们,以修改属于父类的一个字段。我的代码看起来是这样的:
class ClusteringRecord(models.Model):
"""
An abstract class to hold data that is repeated from model to model
"""
wip = models.ForeignKey(
ClusteringWIP, null=True, on_delete = models.SET_NULL)
cluster_comment = models.CharField(max_length=1000, null=True, blank=True)
class Meta:
abstract = True
class ClusteringNPIRecord(ClusteringRecord):
"""Django Model object representing an NPI record that was not able to be
clustered by automatic clustering logic in the database.
"""
npi_id = models.CharField(max_length=1000, null=True)
npi_number = models.CharField(max_length=1000, null=True)
class ClusteringDEARecord(ClusteringRecord):
"""Django Model object representing a DEA record that was not able to be
clustered by automatic clustering logic in the database.
"""
dea_id = models.CharField(max_length=1000, null=True)
dea_number = models.CharField(max_length=1000, null=True)
我想用的代码是这样的:
def cancel_and_return(request, list_type, wip_id):
"""
destroys lock object and returns user to most recent version of worklist
:param request:
:param wip_id: pk of current ClusteringWIP
:return: HTTP redirect to worklist home
"""
wip = ClusteringWIP.objects.select_related().get(pk=wip_id)
for record in wip.clusteringrecord_set.all():
record.cluster_comment = None
record.save()
wip.delete()
但是它告诉我 clusteringrecord_set 是无效的。有没有办法遍历与这个类相关的所有子类?否则我现在用 13 个不同的 for 循环来完成这个任务,这样就违反了 DRY(不要重复自己)原则。
实际上,这个基类适用于所有可能使用 ClusteringWIP 作为外键的 13 个模型,所以简单地遍历所有相关的模型(不管是什么类)就能达到同样的效果。如果这样做是最好的方法,请告诉我。不过,我还是很想知道上面那个问题的答案,以备将来使用。
另外,在寻找答案的过程中,我发现了一个 Django 的 pre_delete 信号,似乎更符合我想要做的事情(也就是在删除 ClusteringWIP 时,将任何相关模型的 'cluster_comment' 字段置为空)。如果有人能给我一个示例,告诉我如何使用这个信号来完成我的任务,我将非常感激。
谢谢。
1 个回答
4
你可以使用ClusteringRecord的subclass()方法。比如说:
@classmethod
def related_set(cls, wip):
classes = cls.__subclasses__()
return sum([c.objects.filter(wip=wip).all() for c in classes], [])
然后用这个方法来遍历你的对象。
对于pre_delete信号,你需要在你的应用程序中有一个signals.py文件,可能看起来像这样:
from django.db.models.signals import pre_delete, post_delete
from django.dispatch import receiver
from myapp.models import ClusteringWIP
@receiver(pre_delete, sender=ClusteringWIP)
def on_instance_delete(sender, instance, **kwargs):
instance.on_pre_delete()
使用ClusteringWIP::on_pre_delete方法,像这样:
def on_pre_delete(self):
for record in ClusteringRecord.related_set(self):
record.cluster_comment = None
record.save()