Django的models中on_delete参数详解

1. 简介

在Django的models中,一些关系型数据库字段的定义中需要使用on_delete参数,用来决定外键在删除时的行为。这个参数的设置对于数据的完整性有着很大的影响,因此需要特别注意。

2. on_delete参数

在Django的models定义中,对于ForeignKey(外键)字段和OneToOneField字段,都需要定义on_delete参数。常见的值有:

models.CASCADE:级联删除。

models.PROTECT:防止删除,引发ProtectedError错误。

models.SET_NULL:将外键字段设置为null,需要定义null=True。

models.SET_DEFAULT:将外键字段设置为默认值,需要定义default。

models.SET():将外键字段设置为指定的值,需要定义一个函数或者取值对象。

2.1 CASCADE级联删除

CASCADE级联删除是最常用的外键删除方式。在删除主表记录时,Django会自动查找所有依赖于该主表记录的外键表记录,并删除这些依赖表的记录。

from django.db import models

class Author(models.Model):

name = models.CharField(max_length=20)

class Article(models.Model):

title = models.CharField(max_length=100)

author = models.ForeignKey(Author, on_delete=models.CASCADE)

上面的代码中,Article表依赖于Author表的主键,默认情况下删除作者记录时将自动删除文章记录:

author = Author.objects.get(name='张三')

author.delete()

2.2 PROTECT防止删除

PROTECT表示防止删除,有些情况下经常使用,例如关联了支付记录的订单记录,不能随便删除订单,否则会引发麻烦:

class Payment(models.Model):

order = models.ForeignKey(Order, on_delete=models.PROTECT)

如果试图删除一个已经有支付记录的订单,将会抛出ProtectedError错误。

2.3 SET_NULL字段置空

当删除主表记录时,设置外键字段为null。在定义一对一关系时,使用OneToOneField()方法,而不是ForeignKey()方法。因为在一对一关系中,外键字段不能存储null值:

class Place(models.Model):

name = models.CharField(max_length=50)

address = models.CharField(max_length=80)

class Restaurant(models.Model):

place = models.OneToOneField(

Place,

on_delete=models.SET_NULL,

null=True,

blank=True,

)

serves_hot_dogs = models.BooleanField(default=False)

serves_pizza = models.BooleanField(default=False)

p1 = Place(name='The Anchor', address='Trafalgar Square, London')

p1.save()

r = Restaurant(place=p1, serves_hot_dogs=False, serves_pizza=True)

r.save()

p1.delete()

在使用SET_NULL将外键字段置null时,必须同时定义该字段可以为null,否则将会抛出IntegrityError错误。

2.4 SET_DEFAULT字段重置为默认值

当删除主表记录时,将外键字段重置为默认值。

class Car(models.Model):

manufacturer = models.ForeignKey(

Manufactory,

on_delete=models.SET_DEFAULT,

default=1,

)

model_name = models.CharField(max_length=32, null=False, blank=False)

mileage = models.FloatField()

def delete_manufactory(manu_pk):

Manufactory.objects.get(pk=manu_pk).delete()

当调用delete_manufactory()删除默认主键为1的品牌记录时,将自动把所有外键对应的车辆品牌设置为默认品牌。

2.5 SET()字段设置为指定值

当删除主表记录时,将外键字段设置为指定的值。这个指定的值可以是常量、其他字段的值或者自定义的处理函数。

def myfunc():

return Manufactory.objects.create(name='Noname') # 返回新创建的品牌实例

class Car(models.Model):

manufacturer = models.ForeignKey(

Manufactory,

on_delete=models.SET(myfunc),

)

model_name = models.CharField(max_length=32, null=False, blank=False)

mileage = models.FloatField()

def delete_manufactory(manu_pk):

Manufactory.objects.get(pk=manu_pk).delete()

当调用delete_manufactory()删除主键为manu_pk的品牌记录时,将自动调用myfunc()函数创建一个新的品牌,并把所有外键对应的车辆品牌设置为新品牌。

3. 批量操作注意事项

批量操作时要特别注意外键关系的完整性。如果不受管理地删除或增加记录,可能会造成表间关系的不一致性。

例如:执行如下代码来删除所有Article数据,此时删除数据的顺序可能难以确定,因此可能会引起ProtectedError错误:

Article.objects.all().delete()

正确的做法是循环删除所有Article记录:

while Article.objects.count() > 0:

article = Article.objects.first()

article.delete()

4. 总结

修改外键在删除主表记录时的表现行为,对于保证数据完整性十分重要。Django的on_delete参数提供了5种常见外键删除方式,可以根据具体应用场景选择适当的方式。同时,在批量操作时需要特别注意,保证数据记录之间的关系不被破坏。

免责声明:本文来自互联网,本站所有信息(包括但不限于文字、视频、音频、数据及图表),不保证该信息的准确性、真实性、完整性、有效性、及时性、原创性等,版权归属于原作者,如无意侵犯媒体或个人知识产权,请来电或致函告之,本站将在第一时间处理。猿码集站发布此文目的在于促进信息交流,此文观点与本站立场无关,不承担任何责任。

后端开发标签