본문 바로가기

python

django에서 queryset을 signal 동작 없이 delete하는 방법

django 에서 queryset 을 delete 할 경우 pre_delete signal과 post_delete signal이 호출됩니다.

 

비즈니스 로직상 또는 상황에 따라 signal 동작을 하지 않고 해당 queryset 삭제가 필요한 경우가 있습니다.

이럴 경우 SQL 쿼리를 다음과 같이 직접 작성해서 삭제하게됩니다.

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("DELETE FROM myapp_mymodel WHERE is_active = %s", [False])

 

DB 캐시를 위해 cacheops 또는 cachalot을 사용하는 경우 SQL 쿼리를 직접 실행할 경우 DB 캐시를 초기화하는 후작업이 필요합니다.

 

Django DB QuerySets의 메소드에는 내부용으로 사용되는 _raw_delete() 라는 메소드가 있습니다.

    def _raw_delete(self, using):
        """
        Delete objects found from the given queryset in single direct SQL
        query. No signals are sent and there is no protection for cascades.
        """
        query = self.query.clone()
        query.__class__ = sql.DeleteQuery
        cursor = query.get_compiler(using).execute_sql(CURSOR)
        if cursor:
            with cursor:
                return cursor.rowcount
        return 0

    _raw_delete.alters_data = True

https://github.com/django/django/blob/d96b6611358b35f89a89d24150e30c260574efc0/django/db/models/query.py#L1203

 

django/django/db/models/query.py at d96b6611358b35f89a89d24150e30c260574efc0 · django/django

The Web framework for perfectionists with deadlines. - django/django

github.com

 

Django DB QuerySets 에서 내부용으로 사용하는 메소드로 사용의 주의가 필요하며 언더바(_)로 시작합니다.

 

_raw_delete를 사용하면 pre_delete signal과 post_delete signal 없이 손쉽게 queryset을 삭제할 수 있습니다.

queryset = MyModel.objects.filter(is_active=False)
queryset._raw_delete()