FYI, on_delete
tham số trong các mô hình là ngược với những gì nó nghe như. Bạn đặt on_delete
Khóa ngoài (FK) trên mô hình để báo cho django biết phải làm gì nếu mục FK mà bạn đang trỏ đến trong hồ sơ của bạn bị xóa. Các tùy chọn cửa hàng của chúng tôi đã sử dụng nhiều nhất là PROTECT
, CASCADE
, và SET_NULL
. Dưới đây là các quy tắc cơ bản tôi đã tìm ra:
- Sử dụng
PROTECT
khi FK của bạn đang trỏ đến một bảng tra cứu thực sự không nên thay đổi và điều đó chắc chắn không nên khiến bảng của bạn thay đổi. Nếu bất cứ ai cố gắng xóa một mục trên bảng tra cứu đó, PROTECT
ngăn họ xóa nó nếu nó được gắn với bất kỳ hồ sơ. Nó cũng ngăn django xóa bản ghi của bạn chỉ vì nó đã xóa một mục trên bảng tra cứu. Phần cuối cùng này là rất quan trọng. Nếu ai đó xóa giới tính "Nữ" khỏi bảng Giới tính của tôi, tôi sẽ KHÔNG muốn xóa ngay lập tức bất kỳ ai và tất cả những người tôi có trong bảng Người có giới tính đó.
- Sử dụng
CASCADE
khi FK của bạn đang trỏ đến một bản ghi "cha mẹ". Vì vậy, nếu một người có thể có nhiều mục PersonEthnicity (anh / cô ấy có thể Mỹ Da Đỏ, Đen, và Trắng), và rằng Người được xóa, tôi thực sự sẽ muốn bất kỳ "con" PersonEthnicity mục bị xóa. Họ không liên quan nếu không có Người.
- Sử dụng
SET_NULL
khi bạn làm muốn mọi người được phép xóa một mục trên một bảng nhìn lên, nhưng bạn vẫn muốn giữ hồ sơ của bạn. Ví dụ: nếu một Người có thể có Trường trung học, nhưng điều đó thực sự không quan trọng với tôi nếu trường cấp ba đó biến mất trên bàn tra cứu của tôi, tôi sẽ nói on_delete=SET_NULL
. Điều này sẽ để lại hồ sơ cá nhân của tôi ra khỏi đó; nó sẽ chỉ đặt FK trung học trên Người của tôi thành null. Rõ ràng, bạn sẽ phải cho phép null=True
trên FK đó.
Dưới đây là một ví dụ về một mô hình thực hiện cả ba điều:
class PurchPurchaseAccount(models.Model):
id = models.AutoField(primary_key=True)
purchase = models.ForeignKey(PurchPurchase, null=True, db_column='purchase', blank=True, on_delete=models.CASCADE) # If "parent" rec gone, delete "child" rec!!!
paid_from_acct = models.ForeignKey(PurchPaidFromAcct, null=True, db_column='paid_from_acct', blank=True, on_delete=models.PROTECT) # Disallow lookup deletion & do not delete this rec.
_updated = models.DateTimeField()
_updatedby = models.ForeignKey(Person, null=True, db_column='_updatedby', blank=True, related_name='acctupdated_by', on_delete=models.SET_NULL) # Person records shouldn't be deleted, but if they are, preserve this PurchPurchaseAccount entry, and just set this person to null.
def __unicode__(self):
return str(self.paid_from_acct.display)
class Meta:
db_table = u'purch_purchase_account'
Là một mẩu tin cuối cùng, bạn có biết rằng nếu bạn không chỉ định on_delete
(hoặc không), thì hành vi mặc định là CASCADE
? Điều này có nghĩa là nếu ai đó đã xóa mục nhập giới tính trên bảng Giới tính của bạn, bất kỳ hồ sơ Người nào có giới tính đó cũng sẽ bị xóa!
Tôi sẽ nói, "Nếu nghi ngờ, hãy thiết lập on_delete=models.PROTECT
." Sau đó đi kiểm tra ứng dụng của bạn. Bạn sẽ nhanh chóng tìm ra FK nào sẽ được gắn nhãn các giá trị khác mà không gây nguy hiểm cho bất kỳ dữ liệu nào của bạn.
Ngoài ra, điều đáng chú ý on_delete=CASCADE
là thực sự không được thêm vào bất kỳ di chuyển nào của bạn, nếu đó là hành vi bạn đang chọn. Tôi đoán điều này là bởi vì nó là mặc định, vì vậy việc đặt on_delete=CASCADE
cũng giống như không đặt gì cả.