# 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/