自定义django模型字段中的`on_delete` param函数



我有一个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.

最新更新