2010-03-19 5 views
49

장고 모델은 일반적으로 (기본적으로 지원하지 않는 데이터베이스에서 작동하는 방식.) 매우 적절 ON DELETE CASCADE 동작을 처리Django의 계단식 삭제 동작을 무시하는 옵션은 무엇입니까?

그러나, 나는이를 대체하는 가장 좋은 방법이 무엇인지 발견하기 위해 사투를 벌인거야 (즉,이 자식 레코드가있는 경우 객체를 삭제 방지) DELETE SET NULL의 ON

  • (즉,하지

    • ON, 제한 삭제 : 그것은 예를 들어 다음과 같은 경우에, 적절하지 않은 행동 자식 레코드를 삭제하지만 그것의 부모 키를 NULL inst로 설정하십시오. 관계를 깨뜨리는 ead)

    • 레코드가 삭제 될 때 다른 관련 데이터를 업데이트하십시오 (예 :.

      • 재정 모델의 delete() 방법 : 업로드 된 이미지 파일)

      다음

      내가 알고 있는데 이들을 달성 할 수있는 잠재력 방법입니다 삭제. 이러한 종류의 작업이 수행되는 동안 QuerySet을 통해 레코드가 삭제되면 종료됩니다. 또한 모든 모델의 delete()은 Django의 코드가 호출되지 않도록해야하며 QuerySet을 사용하여 자식 개체를 삭제할 수 있으므로 super()을 호출 할 수 없습니다.

    • 신호를 사용하십시오. 이는 모델을 직접 삭제하거나 QuerySet을 통해 삭제할 때 호출되므로 이상적인 것으로 보입니다. 그러나 자식 개체가 삭제되지 않도록하여 ON CASCADE RESTRICT 또는 SET NULL을 구현하는 데 사용할 수 없습니다.

    • 이 제대로이 문제를 처리하는 데이터베이스 엔진을 사용

    (... 그리고 그때까지 버그에 살고) 장고가 지원 될 때까지

  • 기다립니다 (장고 무엇을?이 경우에합니까)

    첫 번째 옵션이 유일하게 실행 가능한 것 같지만, 못 생기고 목욕탕에 아기를 던지며 새로운 모델/관계가 추가 될 때 뭔가를 놓칠 위험이 있습니다.

    내가 누락 된 항목이 있습니까? 어떤 추천?

  • 답변

    60

    이 문제를 다루는 사람들을위한 메모 만 있어도 장고 1.3에 기본 제공되는 솔루션이 있습니다.

    자세한 내용은 다음 문서를 참조하십시오. django.db.models.ForeignKey.on_delete Fragments of Code 사이트의 편집자를위한 감사합니다.

    가장 간단한 가능한 시나리오는 모델 FK 필드 정의에 추가

    on_delete=models.SET_NULL 
    
    +8

    일 - 워드 프로세서에 따라 설정이 '외래 키 필드에 대한 on_delete'도 장고 2.0에서 필요합니다. – whusterj

    6

    장고는 CASCADE 동작 만 에뮬레이트합니다. 장고 사용자 그룹 discussion에 따르면

    가장 적절한 솔루션은 다음과 같습니다

    • 는 DELETE SET NULL의 시나리오를 반복하려면 - 수동 obj.delete 전에 (모든 관련 모델) obj.rel_set.clear()를 할().
    • ON DELETE RESTRICT 시나리오를 반복하려면 obj.delete() 전에 수동으로 obj.rel_set이 비어 있는지 확인하십시오.
    4

    다음은 만족스러운 해결책은 아니지만 다음은 내가 해결한 해결책입니다.

    나는 내 모든 모델에 추상 기본 클래스를 추가했습니다 :

    class MyModel(models.Model): 
        class Meta: 
         abstract = True 
    
        def pre_delete_handler(self): 
         pass 
    

    신호 처리기가이 모델의 서브 클래스가 어떤 pre_delete 이벤트를 잡는다 : 내 각 모델에서

    def pre_delete_handler(sender, instance, **kwargs): 
        if isinstance(instance, MyModel): 
         instance.pre_delete_handler() 
    models.signals.pre_delete.connect(pre_delete_handler) 
    

    , 자식 레코드가있는 경우 pre_delete_handler 메서드에서 예외를 throw하여 모든 "ON DELETE RESTRICT"관계를 시뮬레이션합니다.

    class RelatedRecordsExist(Exception): pass 
    
    class SomeModel(MyModel): 
        ... 
        def pre_delete_handler(self): 
         if children.count(): 
          raise RelatedRecordsExist("SomeModel has child records!") 
    

    데이터가 수정되기 전에 삭제가 중단됩니다.

    불행히도 신호를 보내기 전에 삭제할 개체 목록이 Django에 의해 이미 생성되었으므로 pre_delete 신호 (예 : ON DELETE SET NULL을 에뮬레이트)의 데이터를 업데이트 할 수 없습니다. Django는 순환 참조에 걸리는 것을 피하고 불필요하게 여러 번 객체에 신호를 보내지 않도록이 작업을 수행합니다.

    이제 삭제를 수행 할 수 있는지 확인하는 것은 호출 코드의 책임입니다. delete() 메소드를 오버라이드 (override)하는, 내 views.pymodels.py에 너무 많은 코드를 변경하는 것을 방지하기 위해

    class MyModel(models.Model): 
        ... 
        def prepare_delete(self): 
         pass 
    

    이 돕기 위해 각 모델은 self.related_set.clear() 또는 유사한을 통해 NULL에 키를 설정 돌봐 prepare_delete() 방법이있다

    class MyModel(models.Model): 
        ... 
        def delete(self): 
         self.prepare_delete() 
         super(MyModel, self).delete() 
    

    이 예상대로 명시 적으로 obj.delete()를 통해 호출 어떤 삭제가 작동한다는 것을 의미하지만, 삭제가 직렬로 연결된 한 경우 관련 : MyModelprepare_delete()를 호출 d 개체를 사용하거나 queryset.delete()을 통해 이루어지며 호출 코드가 필요한 경우 모든 링크가 끊어지는 것을 보장하지 않으면 pre_delete_handler이 예외를 throw합니다.

    그리고 마지막으로, 나는 post_delete 신호에 전화를 모델이 다른 데이터를 취소 할 수 있습니다 도착 모델과 유사한 post_delete_handler 방법을 추가했습니다 (ImageField들에 대한 예를 삭제 파일을.)

    class MyModel(models.Model): 
        ... 
    
        def post_delete_handler(self): 
         pass 
    
    def post_delete_handler(sender, instance, **kwargs): 
        if isinstance(instance, MyModel): 
         instance.post_delete_handler() 
    models.signals.post_delete.connect(post_delete_handler) 
    

    나는 누군가를 돕고 코드가 너무 많은 문제없이 더 쓸모있는 것으로 다시 스레딩 될 수 있기를 바란다.

    개선 방법에 대한 제안은 환영합니다.

    관련 문제