# https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.fields.files.FieldFile.delete
1. 명시적 삭제 - model이 삭제 될때 첨부파일은 자동으로 삭제 되지 않는다.
   따라서 models.FileField.delete(save=False) <-- save=False 옵션은 변경내용을 DB에 저장하는 query(update, insert)를 하지 않도록 하는 flag
   를 직접 호출해야 한다.

 

# https://docs.djangoproject.com/en/3.0/topics/signals/#module-django.dispatch
2. Signals 이용 - 특정 model이 삭제되고난후(post <- 게시물이 아니고, 後다), receiver에서 event를 수신하여 처리하는 방법이다.

attFile/models.py

from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.auth.models import User
# 2. 방법
from django.db.models.signals import post_delete
from django.dispatch import receiver

class AttFile(models.Model):
    att_uid         = models.AutoField("Attachment File UID", primary_key=True)
    att_name        = models.CharField("Attachment File Name", max_length=256)
    att_file        = models.FileField("Attachment File", upload_to="uploads/%Y/%m/%d/", max_length=512, unique=True, blank=True)
    att_isImage     = models.BooleanField("Image file whether or not", default=False)
    att_desc        = models.CharField("Attachment File Description", max_length=200, null=True, blank=True)
    # https://docs.djangoproject.com/en/3.0/ref/contrib/contenttypes/#generic-relations
    content_type    = models.ForeignKey(ContentType, on_delete=models.PROTECT, related_name="contentType_attFile", db_column="content_type_id", db_index=True, verbose_name="ContentType")
    object_uid      = models.PositiveIntegerField("Related Object UID", db_index=True)
    content_object  = GenericForeignKey("content_type", "object_uid")
    att_crte_user   = models.ForeignKey(User, on_delete=models.PROTECT, related_name="att_post_creator", db_column="att_crte_user_id", default=User, editable=False, verbose_name="Creator")
    att_crte_dt     = models.DateTimeField("Created DateTime", auto_now_add=True)
    att_mdfy_user   = models.ForeignKey(User, on_delete=models.PROTECT, related_name="att_post_modifier", db_column="att_mdfy_user_id", default=User, editable=False, verbose_name="Modifier")
    att_mdfy_dt     = models.DateTimeField("Modified DateTime", auto_now=True)

    class Meta:
        verbose_name        = "attFile"
        verbose_name_plural = "attFiles"
        db_table            = "blog_attFile"
        ordering            = ["att_uid"]
        
    def __str__(self):
        return self.att_name
    
    # 1. 방법
    def attFileDelete(self):
        self.att_file.delete(save=False)
        

# 2. 방법
@receiver(post_delete, sender=AttFile)
def deleteAttFile(sender, **kwargs):
    attFile = kwargs.get("instance")
    attFile.att_file.delete(save=False)

 

 

post/models.py

...

class Post(models.Model):
    post_uid        = models.AutoField("Post UID", primary_key=True)
    post_title      = models.CharField("Post Title", max_length=100)
    post_slug       = models.SlugField("Post Slug", max_length=100, unique=False, allow_unicode=True, help_text="one word for title alias.")
    post_content    = models.TextField("Post Content")
    post_views      = models.PositiveIntegerField("Views", default=0)
    post_isEnabled  = models.BooleanField("Enabled", default=True)
    post_tag        = TagField()
    # https://docs.djangoproject.com/en/3.0/ref/contrib/contenttypes/#reverse-generic-relations
    # if you delete a post that has an GenericRelation, attFile object which have a GenericForeignKey pointing at it will be deleted as well. at the same time. 
    attFile         = GenericRelation(AttFile, related_query_name="post", content_type_field="content_type_id", object_id_field="object_uid")
    menu            = models.ForeignKey(Menu, on_delete=models.PROTECT, related_name="menu_post", db_column="menu_uid", db_index=True, verbose_name="Menu")
    post_crte_user  = models.ForeignKey(User, on_delete=models.PROTECT, related_name="user_post_creator", db_column="post_crte_user_id", default=User, editable=False, verbose_name="Creator")
    post_crte_dt    = models.DateTimeField("Created DateTime", auto_now_add=True)
    post_mdfy_user  = models.ForeignKey(User, on_delete=models.PROTECT, related_name="user_post_modifier", db_column="post_mdfy_user_id", default=User, editable=False, verbose_name="Modifier")
    post_mdfy_dt    = models.DateTimeField("Modified DateTime", auto_now=True)

...

    # 1. 방법
    def delete(self, using=None, keep_parents=False):
         for attFile in AttFile.objects.filter(post__post_uid=self.post_uid):
             attFile.attFileDelete()
            
        return models.Model.delete(self, using=using, keep_parents=keep_parents)

위 예제에서는 Signals code를 models module에 있으나

django.dispatch.receiver : https://docs.djangoproject.com/en/4.1/topics/signals/#django.dispatch.receiver

django.apps.AppConfig.ready : https://docs.djangoproject.com/en/4.1/ref/applications/#django.apps.AppConfig.ready

위와 같은 이유로 하위모듈(signals.py)로 분리하여 Application configuration class(apps.py)의 ready method에서 연결하는걸 추천한다.

https://www.geeksforgeeks.org/how-to-create-and-use-signals-in-django/