2009-06-22 3 views
1

다음 설정을 사용하여 장고에서 소프트 삭제를 구현합니다. 내가 후드 아래 장고에 익숙하지 않아서 만날지도 모르는 것에 대한 의견을 보내 주시면 감사하겠습니다. 나는 특히 QuerySet을 서브 클래스 화하는 것을 불편하게 느낀다.동일한 테이블 Django ORM 소프트 삭제 방법 알았습니까?

기본적인 아이디어는 MyModeldelete에 대한 첫 번째 호출은 현재 날짜에 MyModeldate_deleted을 변경한다는 것입니다. 두 번째 delete은 실제로 개체를 삭제합니다. 삭제 된 개체를 숨길 기본 관리부터 (A delete를 잡는 것은 두 오버라이드 (override), 객체의 delete 방법을 우회 할 수있는 QuerySet에있는 개체에 대한 하나 하나를. 필요), 삭제 된 개체가 사라 명시 적으로 deleted_objects 관리자를 통해 요청해야합니다.

이 설정을 사용하면 DeletionQuerySetDeletionManager을 정의하고 모델 (들)에 date_deleted, objectsdeleted_objects를 추가해야합니다.

감사합니다,

추신, 필터링이 방법은 관리자가 strongly discouraged입니다 기본에서 개체를 언급하는 것을 잊었다!

class DeletionQuerySet(models.query.QuerySet): 

    def delete(self): 
     prev_deleted = self.filter(date_deleted__isnull=False) 
     prev_deleted.actual_delete() 
     prev_undeleted = self.filter(date_deleted__isnull=True) 
     prev_undeleted.update(date_deleted=datetime.datetime.now()) 

    def actual_delete(self): 
     super(DeletionQuerySet, self).delete() 

class DeletionManager(models.manager.Manager): 

    # setting use_for_related_fields to True for a default manager ensures 
    # that this manager will be used for chained lookups, a la double underscore, 
    # and therefore that deleted Entities won't popup unexpectedly. 
    use_for_related_fields = True 

    def __init__(self, hide_deleted=False, hide_undeleted=False): 
     super(DeletionManager, self).__init__() 
     self.hide_deleted = hide_deleted 
     self.hide_undeleted = hide_undeleted 

    def get_query_set(self): 
     qs = DeletionQuerySet(self.model) 
     if self.hide_deleted: 
      qs = qs.filter(date_deleted__isnull=True) 
     if self.hide_undeleted: 
      qs = qs.filter(date_deleted__isnull=False) 
     return qs 

class MyModel(models.Model): 

    # Your fields here... 
    date_deleted = models.DateTimeField(null=True) 

    #the first manager defined in a Model will be the Model's default manager 
    objects = DeletionManager(hide_deleted=True) 
    deleted_objects = DeletionManager(hide_undeleted=True) 

    def delete(self): 
     if self.date_deleted is None: 
      self.date_deleted = datetime.datetime.now() 
      self.save() 
     else: 
      super(Agreement, self).delete() 
+3

한 가지 문제는 계단식 삭제입니다. 이 설정은 외래 키에 삭제를 알리는 일을하지 않습니다. 관련 엔티티가 (분명히 유효한) 외래 키를 따라 'MyModel'을 따라 가려고하면 아무 것도 얻을 수 없습니다. 프로그래머가 계단식 소프트 삭제를 구현한다고해도 모델의 기본 관리자가 서로 삭제 된 레코드를 숨길 때 소프트 삭제 된 모델이 서로를 어떻게 참조합니까? –

+0

내 대답보기. 그것은 우리를 위해 잘 작동했습니다. 삭제 된 모델을 제외시키고 자하는 쿼리에서 객체 대신 object_soft를 사용하십시오. 이 방법은 외래 키 조회가 여전히 발생할 수 있습니다. https://stackoverflow.com/questions/42123972/django-orm-soft-delete-objects-with-flag-but-still-beable-to-look-them-up-in/47986069#47986069 –

답변

1

저는 현재 사용중인 인기있는 기술에 대해 아무 것도 생각하지 못하는데, 문제는 도메인에 무관심하고 일반적인 소프트 삭제가 있습니다. 나는 그것이 우리가 사용하는 것보다 역사/역사 중심의 데이터베이스 시스템에 더 연관되어 있다고 생각한다. django의 삭제 (하드 삭제)를 회피하지 않는 것이 좋습니다. 있는 그대로 유지.

당신의 특정 도메인에 대한 삭제와 동의어를 찾아보십시오, 이와 관련하여

... 경우, 시각적 삭제의 90 %에, 당신이 가장 가능성이 우리의 시스템에있는 것이다 "삭제" 문제를 해결하고 프로젝트 시작시이를 수행하십시오.

때문에 ...에서 IsVisible, IsUnpublished (심지어 isDeleted를) 엉망 쿼리, 그들은 당신이 항상 포함하도록주의해야한다는 불평

불평하지만이 경우, 분명히 도메인 문제의 무지 도메인에는 보이지 않게 만들거나 비공개로 만들 수있는 개체가 있습니다. 물론 표시하려는 모든 개체의 목록을 쿼리 할 때 볼 수 없거나 게시되지 않은 개체를 모두 START에서 QUERY해야합니다. 도메인 문제는 완전한 형태로 해결됩니다.

건배.

관련 문제