我有一个ipv4manage模型,其中我有一个vlanedipv4network
字段:
class IPv4Manage(models.Model):
...
vlanedipv4network = models.ForeignKey(
to=VlanedIPv4Network, related_name="ipv4s", on_delete=models.xxx, null=True)
我们知道,在on_delete
参数上,我们将一般填充models.xxx
,例如models.CASCADE
。
是否可以自定义功能,填充在那里?我想在那里做其他逻辑。
可以在django/db/models/deletion.py
on_delete
的选择例如,model.set_null的实现为:
def SET_NULL(collector, field, sub_objs, using):
collector.add_field_update(field, None, sub_objs)
和models.cascade(稍微复杂得多)被实现为:
def CASCADE(collector, field, sub_objs, using):
collector.collect(sub_objs, source=field.remote_field.model,
source_attr=field.name, nullable=field.null)
if field.null and not connections[using].features.can_defer_constraint_checks:
collector.add_field_update(field, None, sub_objs)
因此,如果您弄清楚这些参数是什么,那么您应该能够定义自己的函数以传递到模型字段的on_delete
参数。collector
很可能是Collector
的实例(在同一文件中定义,不确定确切的用途),field
很可能是删除模型字段,sub_objs
可能是该字段与对象相关的实例,using
表示该字段使用数据库。
也有用于删除的自定义逻辑的替代方法,否则对您来说,毫不掩饰on_delete可能有点过高。
POST_DELETE和PRE_DELETE允许您定义一些自定义逻辑以在删除实例之前或之后运行。
from django.db.models.signals import post_save
def delete_ipv4manage(sender, instance, using):
print('{instance} was deleted'.format(instance=str(instance)))
post_delete.connect(delete_ipv4manage, sender=IPv4Manage)
最后,您可以覆盖模型/QuerySet的delete()
方法,但是使用此方法请注意具有批量删除的警告:
在批量操作中未调用覆盖模型方法
请注意,当使用QuerySet或由于级联删除而批量删除对象时,不一定调用对象的delete()方法。为了确保执行自定义删除逻辑,您可以使用pre_delete和/或post_delete信号。
另一个有用的解决方案是使用models.SET()
,您可以在其中传递函数(在下面的示例中deleted_guest)
guest = models.foreignkey('guest',on_delete = models.set.set(deleted_guest))
,函数deleted_guest是
DELETED_GUEST_EMAIL = 'deleted-guest@introtravel.com'
def deleted_guest():
""" used for setting the guest field of a booking when guest is deleted """
from intro.models import Guest
from django.conf import settings
deleted_guest, created = Guest.objects.get_or_create(
first_name='Deleted',
last_name='Guest',
country=settings.COUNTRIES_FIRST[0],
email=DELETED_GUEST_EMAIL,
gender='M')
return deleted_guest
您无法发送任何参数,并且必须小心循环导入。就我而言,我只是设置填充记录,因此父模型有一个预定义的访客来表示已删除的访客。有了新的GDPR规则,我们必须能够删除来宾信息。
级联和保护等实际上是功能,因此您应该能够在那里注入自己的逻辑。但是,将需要对代码进行一定量的检查,以确切地确定如何获得所需的效果。
取决于您想做的事情可能相对容易,例如,保护功能会引起例外:
def PROTECT(collector, field, sub_objs, using):
raise ProtectedError(
"Cannot delete some instances of model '%s' because they are "
"referenced through a protected foreign key: '%s.%s'" % (
field.remote_field.model.__name__, sub_objs[0].__class__.__name__, field.name
),
sub_objs
)
但是,如果您想要更复杂的东西,则必须了解collector
在做什么,这肯定是可以发现的。
请参阅django.db.models.dealtion的来源。
没有什么可以阻止您添加自己的逻辑。但是,您需要考虑多个因素,包括与所使用的数据库的兼容性。
在大多数用例中,如果您的数据库设计正确,则开箱即用的逻辑已经足够好。请在此处查看您的可用选项https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.foreignkey.on_delete.