Django 모델에서 on_delete는 무엇을합니까?


348

나는 Django에 대해 잘 알고 있지만 최근 on_delete=models.CASCADE에는 모델에 대한 옵션 이 있음을 발견 했으며 같은 문서를 검색했지만 더 이상 찾을 수 없었습니다.

장고 1.9에서 변경 :

on_delete이제 두 번째 위치 인수로 사용할 수 있습니다 (이전에는 일반적으로 키워드 인수로만 전달됨). Django 2.0에서는 필수 인수입니다.

사용 사례는

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass

on_delete는 무엇을합니까? ( 모델이 삭제되면 수행해야 할 작업 )

무엇을 models.CASCADE합니까? ( 문서의 힌트 )

다른 옵션을 사용할 수 있습니까 ( 내 추측이 맞다면 )?

이에 대한 문서는 어디에 있습니까?


비슷한 질문에 대한 답변도 stackoverflow.com/questions/47914325/…
HelenM

1
이 비슷한 질문의 텍스트가 이제이 답변에 아래에 나열되어 있습니다. "FYI, 모델의 on_delete 매개 변수는 소리가 거꾸로되어 있습니다." 원래 답변보다 훨씬 자세한 정보를 제공합니다.
HelenM

답변:


784

이것은 참조 된 객체가 삭제 될 때 채택하는 동작 입니다. django에만 국한된 것은 아니며 SQL 표준입니다.

이러한 이벤트가 발생할 때 수행 할 수있는 6 가지 가능한 조치가 있습니다.

  • CASCADE: 참조 된 오브젝트가 삭제되면 해당 오브젝트를 참조하는 오브젝트도 삭제하십시오 (예를 들어 블로그 게시물을 제거 할 때 주석도 삭제하려고 할 수 있음). SQL에 상응하는 내용 : CASCADE.
  • PROTECT: 참조 된 객체의 삭제를 금지합니다. 삭제하려면 수동으로 참조하는 모든 객체를 삭제해야합니다. SQL에 상응하는 내용 : RESTRICT.
  • SET_NULL: 참조를 NULL로 설정하십시오 (필드가 널 입력 가능해야 함). 예를 들어, 사용자를 삭제할 때 블로그 게시물에 게시 한 주석은 유지하지만 익명 (또는 삭제 된) 사용자가 게시 한 것으로 말할 수 있습니다. SQL에 상응하는 내용 : SET NULL.
  • SET_DEFAULT: 기본값을 설정합니다. SQL에 상응하는 내용 : SET DEFAULT.
  • SET(...): 주어진 값을 설정합니다. 이것은 SQL 표준의 일부가 아니며 Django가 전적으로 처리합니다.
  • DO_NOTHING: 데이터베이스에 무결성 문제 (실제로는 존재하지 않는 개체 참조)가 발생할 수 있으므로 매우 나쁜 아이디어 일 수 있습니다. SQL에 상응하는 내용 : NO ACTION.

출처 : Django documentation

예를 들어 PostGreSQL의 문서 도 참조하십시오 .

대부분의 경우 CASCADE예상되는 동작이지만 모든 ForeignKey에 대해 항상이 상황에서 예상되는 동작이 무엇인지 자문해야합니다. PROTECT그리고 SET_NULL종종 유용하다. CASCADE원하지 않는 위치를 설정 하면 단일 사용자를 삭제하여 모든 데이터베이스를 계단식으로 삭제할 수 있습니다.


계단식 방향을 명확하게하기위한 추가 참고 사항

CASCADE행동 의 방향이 많은 사람들에게 명확하지 않다는 것을 알아 두는 것이 재미있다 . 사실, 그 통지에 재미 CASCADE 조치가 명확하지 않다. 캐스케이드 동작이 혼동 될 수 있음을 이해하지만 다른 동작과 동일한 방향 이라고 생각해야합니다 . 따라서 CASCADE지시가 명확하지 않다고 생각되면 실제로 on_delete행동이 명확하지 않다는 것을 의미 합니다.

데이터베이스에서 외래 키는 기본적으로 정수 필드로 표시되며 값은 외래 객체의 기본 키입니다. 항목 article_B에 대한 외래 키 가있는 항목 comment_A 가 있다고 가정 해 봅시다 . 당신이 항목을 삭제하면 comment_A을 , 모든 벌금입니다 article_B이 없이 살았 comment_A 과이 삭제됩니다 경우 귀찮게하지 않습니다. 그러나, 당신은 삭제 article_B을 한 후, comment_A의 패닉! 그것은 article_B 없이는 살지 않았으며 그것을 필요로합니다. 그것은 그것의 속성의 일부입니다 ( 그러나 * article_B ** ???는 무엇입니까). 이 무결성 오류 를 해결하는 방법을 결정하기위한 단계입니다.article=article_Bon_delete다음과 같이 말하면됩니다.

  • "아니오! 제발! 하지마! 난 너 없이는 살 수 없어!" ( PROTECTSQL 언어로 알려짐)
  • "나는 당신을 아니에요 경우 좋아는, 그때는 아무도 해요" (라고한다 SET_NULL)
  • "안녕 세상에, article_B 없이는 살 수 없어" 자살 (이것은 CASCADE행동입니다).
  • "괜찮아, 여분의 애인이있어, 지금부터 article_C를 참조 할 것이다" ( SET_DEFAULT또는 심지어 SET(...)).
  • "나는 현실에 직면 할 수 없다, 그것이 나에게 남아있는 유일한 것이더라도 계속 너의 이름을 부르겠다!" ( DO_NOTHING)

캐스케이드 방향이 더 명확 해지기를 바랍니다. :)


19
바보 같은 질문이지만 캐스케이드는 항상 하나의 방향성이어야합니까? 즉 Comment , 외래 키가 있으면 BlogPostBlogPost를 삭제하면 Comment가 삭제되어야하지만, Comment를 삭제하면 RDMS에 관계없이 BlogPost가 삭제되지 않아야합니까?
Anthony Manning-Franklin

20
@AnthonyManningFranklin은 물론이다. 삭제시 참조가 "깨진"경우에만 트리거됩니다. 참조를 동시에 삭제하기 때문에 주석을 삭제할 때는 그렇지 않습니다.
Antoine Pinsard

6
문제는 바보가 아닙니다. 나도 그 설명이 필요하다. 그래서 우리는 관계가 일방적이라고 가정하고 관계의 소유자 Comment는 테이블에 FK 필드를 가지고 있고 , 실제 모델에 대해 이야기한다면 BlogPost" 소유자 " Comment입니다. 좋은.
WesternGun

3
Django에서 on_delete를 설정하면 데이터베이스 자체에 ON DELETE 절이 생성되지 않습니다. 지정된 동작 (예 : CASCADE)은 Django를 통해 수행 된 삭제에만 영향을 미치며 데이터베이스에서 직접 수행 된 원시 삭제는 영향을 미치지 않습니다.
JoeMjr2

2
마지막에 나오는 인용문은 Roy Lichtenstein의 만화 패널에서 직접 가져온 것처럼 보입니다! 놀라운
공습

42

on_delete방법은 삭제 한 모델 인스턴스에 의존하는 모델 인스턴스로 수행 할 작업을 Django에 알리는 데 사용됩니다. (예 : ForeignKey관계). 은 on_delete=models.CASCADE즉뿐만 아니라 종속 모델을 삭제 계속 삭제 효과를 계단식으로 장고를 알려줍니다.

보다 구체적인 예는 다음과 같습니다. 당신은이 가정 Author인 모델 ForeignKeyA의 Book모델을. 이제 Author모델 의 인스턴스를 삭제하면 Django는 해당 Book모델의 인스턴스에 의존 하는 모델의 인스턴스로 수행 할 작업을 알 수 없습니다 Author. 이 on_delete방법은 Django에게이 경우 수행 할 작업을 알려줍니다. 설정 on_delete=models.CASCADE하면 Django가 삭제 효과를 계단식으로 표시합니다. 즉, 삭제 한 Book모델 인스턴스에 따라 모든 모델 인스턴스가 Author삭제됩니다.

참고 : on_deleteDjango 2.0에서는 필수 인수가됩니다. 이전 버전에서는 기본값이 CASCADE입니다.

전체 공식 문서는 다음과 같습니다.


37

참고로, on_delete모델 의 매개 변수는 원래의 소리와 반대입니다. on_delete레코드에서 가리키고있는 FK 항목이 삭제 된 경우 django에 수행 할 작업을 알려주기 위해 모델에 외래 키 (FK)를 착용 합니다. 옵션 저희 가게는 대부분이 사용하고 PROTECT, CASCADE하고 SET_NULL. 내가 알아 낸 기본 규칙은 다음과 같습니다.

  1. 사용하다 PROTECT 하여 FK 정말 변경해서는 안하고가하는 룩업 테이블을 가리키는 경우 확실히 변화에 테이블을 야기해서는 안된다. 해당 룩업 테이블에서 항목을 삭제하려고 PROTECT하면 레코드에 묶여 있으면 삭제되지 않습니다. 또한 방지 삭제에서 장고 당신 은 룩업 테이블에서 항목을 삭제해서 기록을. 이 마지막 부분이 중요합니다. 누군가가 성별 테이블에서 성별 "여성"을 삭제하려는 경우, 본인은 해당 성별을 가진 Person 테이블에있는 모든 사람을 즉시 삭제하기를 원하지 않습니다.
  2. 사용하다 CASCADEFK가 "부모"레코드를 가리킬 때 . 사람이 많은 PersonEthnicity 항목을 가질 수 있습니다 경우에 따라서, (그 / 그녀는 아메리칸 인디언, 흑인과 백인이 될 수 있습니다), 그리고 사람이 있다고 한다 삭제, 난 정말 것이다 어떤 "아이"PersonEthnicity 항목을 삭제하고 싶습니다. 그것들은 사람 없이는 관련이 없습니다.
  3. SET_NULL당신이 할 때 사용 않는 사람들이 룩업 테이블에서 항목을 삭제하도록 허용 할,하지만 당신은 여전히 당신의 기록을 보존하고자합니다. 예를 들어, 한 사람이 HighSchool을 가질 수 있지만 해당 고등학교가 내 룩업 테이블에서 사라지면 실제로 중요하지 않습니다 on_delete=SET_NULL. 이것은 내 개인 기록을 거기에 남겨 둘 것입니다. 내 Person의 고등학교 FK를 null로 설정했을뿐입니다. 분명히, 당신은 null=True그 FK 를 허용해야합니다 .

다음은 세 가지를 모두 수행하는 모델의 예입니다.

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'

마지막 골치 아픈 사람 이 아니라면 지정on_delete (또는 지정 하지 않은 경우) 기본 동작은 CASCADE? 이는 누군가 성별 테이블에서 성별 항목을 삭제 한 경우 해당 성별을 가진 모든 사람 레코드도 삭제되었음을 의미합니다.

나는 "의심 스럽다면 설정 on_delete=models.PROTECT하십시오" 라고 말할 것입니다 . 그런 다음 응용 프로그램을 테스트하십시오. 데이터를 위험에 빠뜨리지 않고 어떤 FK에 다른 값을 표시해야하는지 신속하게 파악할 수 있습니다.

또한 on_delete=CASCADE선택한 동작 인 경우 실제로는 마이그레이션에 추가되지 않습니다. 나는 이것이 기본값이기 때문에 추측합니다 on_delete=CASCADE. 퍼팅은 아무것도 넣지 않는 것과 같습니다.


12

앞에서 언급했듯이 CASCADE는 외래 키가있는 레코드를 삭제하고 삭제 된 다른 개체를 참조합니다. 예를 들어 부동산 웹 사이트가 있고 도시를 참조하는 부동산이있는 경우

class City(models.Model):
    # define model fields for a city

class Property(models.Model):
    city = models.ForeignKey(City, on_delete = models.CASCADE)
    # define model fields for a property

이제 도시가 데이터베이스에서 삭제되면 모든 관련 속성 (예 : 해당 도시에있는 부동산)도 데이터베이스에서 삭제됩니다.

이제 SET_NULL 또는 SET_DEFAULT 또는 DO_NOTHING과 같은 다른 옵션의 장점을 언급하고 싶습니다. 기본적으로 관리 관점에서 해당 레코드를 "삭제"하려고합니다. 그러나 당신은 그들이 사라지기를 정말로 원하지 않습니다. 여러 이유들로. 누군가 실수로 삭제했거나 감사 및 모니터링을 위해 삭제했을 수 있습니다. 그리고 평범한보고. 따라서 도시에서 재산을 "분리"하는 방법이 될 수 있습니다. 다시 말하지만, 신청서 작성 방법에 따라 다릅니다.

예를 들어, 일부 응용 프로그램에는 "삭제 된"필드가 0 또는 1입니다. 모든 검색 및 목록보기 등 보고서 또는 사용자가 프런트 엔드에서 액세스 할 수있는 모든 위치 등은 제외됩니다 deleted == 1. 그러나 사용자 정의 보고서 또는 사용자 정의 조회를 작성하여 삭제 된 레코드 목록을 풀다운하여 레코드를 마지막으로 수정 한시기 (다른 필드) 및 사용자 (예 : 누가 삭제 한시기 및시기)를 확인할 수 있습니다. 그것은 경영진의 입장에서 매우 유리합니다.

그리고 deleted = 0그 기록 만큼 간단하게 실수로 삭제 한 내용을 되돌릴 수 있습니다 .

내 요점은 기능이 있다면 그 뒤에 항상 이유가 있다는 것입니다. 항상 좋은 이유는 아닙니다. 그러나 이유가 있습니다. 그리고 종종 좋은 것도 있습니다.


3
이것은 CASCADE가 어느 방향으로 발생하는지 명확하게했기 때문에 도움이되었습니다. SQL 계단식에 익숙하지 않은 경우 허용되는 대답이 명확하지 않습니다.
codescribblr 2015 년

감사합니다 :) 감사합니다!
George Mogilevsky

2
이 답변은 관계 모델의 방향에 대한 나의 의심에 응답하기 때문에이 답변을지지했다
edepe

6

다음은 귀하의 질문에 대한 답변입니다. 왜 우리는 on_delete를 사용합니까?

ForeignKey가 참조하는 객체가 삭제되면 Django는 기본적으로 SQL 제약 조건 ON DELETE CASCADE의 동작을 에뮬레이트하고 ForeignKey를 포함하는 객체를 삭제합니다. on_delete 인수를 지정하여이 동작을 대체 할 수 있습니다. 예를 들어 nullable ForeignKey가 있고 참조 된 개체가 삭제 될 때 null로 설정하려는 경우 :

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

on_delete에 가능한 값은 django.db.models에 있습니다.

캐스케이드 : 캐스케이드가 삭제됩니다. 디폴트

보호 : django.db.IntegrityError의 서브 클래스 인 ProtectedError를 발생시켜 참조 된 오브젝트의 삭제를 방지하십시오.

SET_NULL : ForeignKey를 null로 설정하십시오. null이 True 인 경우에만 가능합니다.

SET_DEFAULT : ForeignKey를 기본값으로 설정하십시오. ForeignKey의 기본값을 설정해야합니다.


sql 및 django와 성숙하지 않기 때문에 간단한 단어가 나에게 분명합니다. 감사합니다.
wm.p1us

3

Person 이라는 모델 과 Companies 라는 모델이 있다고 가정 해 봅시다 .

정의에 따라 한 사람이 여러 회사를 만들 수 있습니다.

회사에 한 사람 만있을 수 있다는 점을 고려하면, 사람이 삭제 될 때 해당 사람과 연관된 모든 회사도 삭제되기를 원합니다.

먼저 Person 모델을 생성합니다.

class Person(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.id+self.name

그러면 회사 모델은 다음과 같습니다.

class Companies(models.Model):
    title = models.CharField(max_length=20)
    description=models.CharField(max_length=10)
    person= models.ForeignKey(Person,related_name='persons',on_delete=models.CASCADE)

on_delete=models.CASCADE회사 모델에서 사용법을 확인 하십시오. 즉, 회사를 소유 한 사람 (Person 클래스의 인스턴스)이 삭제 될 때 모든 회사를 삭제하는 것입니다.


1

기존 캐스케이드 (예 : 폭포)에 FK를 추가하여 "CASCADE"기능의 정신 모델 방향을 다시 지정하십시오. 이 폭포의 출처는 기본 키입니다. 흐름을 삭제합니다.

따라서 FK의 on_delete를 "CASCADE"로 정의하면이 FK의 레코드를 PK에서 발생하는 일련의 삭제에 추가합니다. FK의 기록은이 계단식에 참여하거나 참여하지 않을 수 있습니다 ( "SET_NULL"). 실제로 FK가있는 레코드는 삭제의 흐름을 방해 할 수도 있습니다! "PROTECT"로 댐을 만드십시오.


0

CASCADE를 사용 한다는 것은 실제로 Django에게 참조 된 레코드를 삭제하도록 지시하는 것을 의미합니다. 아래 설문 조사 앱 예에서 : '질문'이 삭제되면이 질문의 선택도 삭제됩니다.

예 : 질문 : 우리에 대해 어떻게 알게 되셨습니까? (선택 : 1. 친구 2. TV 광고 3. 검색 엔진 4. 이메일 프로모션)

이 질문을 삭제하면 표에서이 네 가지 선택 사항도 모두 삭제됩니다. 흐르는 방향에 유의하십시오. 질문 모델에 on_delete = models.CASCADE를 넣을 필요는 없습니다.

from django.db import models



class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.dateTimeField('date_published')

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_legth=200)
    votes = models.IntegerField(default=0)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.