Soft Delete๋? ๐
1. Soft Delete ์ ์
Soft Delete(์ํํธ ๋๋ฆฌํธ)๋ ๋ฐ์ดํฐ๋ฅผ ์ค์ ๋ก ์ญ์ ํ๋ ๋์ , ํน์ ์ปฌ๋ผ(์: `deleted_at` ๋๋`is_deleted`)์ ์ ๋ฐ์ดํธํ์ฌ ๋ ผ๋ฆฌ์ ์ผ๋ก ์ญ์ ๋ ๊ฒ์ฒ๋ผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด๋ค.
๐ Hard Delete vs. Soft Delete
๊ตฌ๋ถ | Hard Delete | Soft Delete |
๋ฐ์ดํฐ ์ญ์ ์ฌ๋ถ | ์ค์ ์ญ์ | DB์ ๋จ์์์ |
๋ณต๊ตฌ ๊ฐ๋ฅ ์ฌ๋ถ | ๋ถ๊ฐ๋ฅ | ๊ฐ๋ฅ |
์ฑ๋ฅ ์ํฅ | ๋น ๋ฆ | ์ผ๋ถ ์ฑ๋ฅ ๋ถ๋ด |
๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ | ์์กด์ฑ ๋ฐ์ดํฐ ์ญ์ ํ์ | ์ ์ง ๊ฐ๋ฅ |
์ฌ์ฉ ์ฌ๋ก | ๋ณด์์ด ์ค์ํ ๋ฐ์ดํฐ | ๊ธฐ๋ก ๋ณด์กด์ด ์ค์ํ ๊ฒฝ์ฐ |
2. Soft Delete ๊ตฌํ ๋ฐฉ์
1๏ธโฃ `is_deleted` ํ๋๊ทธ ํ์ฉ
์ญ์ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ Boolean ์ปฌ๋ผ์ ์ถ๊ฐํ๋ ๋ฐฉ์.
ALTER TABLE users ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE;
UPDATE users SET is_deleted = TRUE WHERE id = 1;
SELECT * FROM users WHERE is_deleted = FALSE;
์ฅ์ : ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ๋น ๋ฆ
๋จ์ : ์ค๋ณต ๋ฐ์ดํฐ๊ฐ ๋จ์ ์ ์์
2๏ธโฃ `deleted_at`(ํ์์คํฌํ) ํ์ฉ
์ญ์ ๋ ์๊ฐ์ ๊ธฐ๋กํ๋ ๋ฐฉ์.
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMP NULL;
UPDATE users SET deleted_at = NOW() WHERE id = 1;
SELECT * FROM users WHERE deleted_at IS NULL;
์ฅ์ : ์ญ์ ์์ ๊ธฐ๋ก ๊ฐ๋ฅ, ๋ณต๊ตฌ ์ฉ์ด
๋จ์ : ์ถ๊ฐ์ ์ธ ์ธ๋ฑ์ฑ์ด ํ์ํ ์ ์์
3๏ธโฃ ๋ณ๋ ํ ์ด๋ธ์ ๋ณด๊ด
์ญ์ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ํ ์ด๋ธ(`users_deleted`)๋ก ์ด๋ํ๋ ๋ฐฉ์.
INSERT INTO users_deleted SELECT * FROM users WHERE id = 1;
DELETE FROM users WHERE id = 1;
์ฅ์ : ์ฑ๋ฅ ์ต์ ํ ๊ฐ๋ฅ, ์๋ณธ ๋ฐ์ดํฐ ์ ์ง
๋จ์ : ํ
์ด๋ธ ๊ด๋ฆฌ๊ฐ ๋ณต์กํด์ง ์ ์์
3. Soft Delete์ ์ฅ์ ๊ณผ ๋จ์
โ ์ฅ์
- ๋ฐ์ดํฐ ๋ณต๊ตฌ ๊ฐ๋ฅ: ์ค์๋ก ์ญ์ ํด๋ ๋ณต๊ตฌ ๊ฐ๋ฅ
- ๊ฐ์ฌ ๋ก๊ทธ ๋ฐ ๋ณ๊ฒฝ ์ด๋ ฅ ์ ์ง: ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ ์ ์ง
- ์ฐ๊ด ๋ฐ์ดํฐ ๋ณดํธ: ์ธ๋ ํค(FOREIGN KEY) ์ ์ฝ ์กฐ๊ฑด์ ์ฝ๊ฒ ์ ์ง
โ ๋จ์
- ์ฟผ๋ฆฌ ๋ณต์ก์ฑ ์ฆ๊ฐ: ํญ์ `WHERE is_deleted = FALSE` ๋๋ `WHERE deleted_at IS NULL` ์กฐ๊ฑด์ ์ถ๊ฐํด์ผ ํจ
- ๋ฐ์ดํฐ ์ ๋ฆฌ ํ์: ์ค๋๋ ๋ฐ์ดํฐ๊ฐ ์์ด๋ฉด ์ฑ๋ฅ ์ ํ ๊ฐ๋ฅ
- ์ธ๋ฑ์ค ๊ด๋ฆฌ ํ์: ๊ฒ์ ์ฑ๋ฅ ์ ์งํ๊ธฐ ์ํด ์ถ๊ฐ์ ์ธ ์ธ๋ฑ์ฑ ํ์
4. Django์์ Soft Delete ๊ตฌํํ๊ธฐ
Django์์๋ `QuerySet`์ ์ปค์คํฐ๋ง์ด์งํ์ฌ Soft Delete๋ฅผ ์ ์ฉํ ์ ์๋ค.
1๏ธโฃ `is_deleted` ํ๋๊ทธ ๋ฐฉ์
from django.db import models
class SoftDeleteManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(is_deleted=False)
class User(models.Model):
name = models.CharField(max_length=255)
is_deleted = models.BooleanField(default=False)
objects = SoftDeleteManager() # ๊ธฐ๋ณธ์ ์ผ๋ก ์ญ์ ๋ ๋ฐ์ดํฐ๋ ๋ณด์ด์ง ์์
def delete(self):
self.is_deleted = True
self.save()
2๏ธโฃ `deleted_at` ๋ฐฉ์
from django.db import models
from django.utils.timezone import now
class SoftDeleteManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(deleted_at__isnull=True)
class User(models.Model):
name = models.CharField(max_length=255)
deleted_at = models.DateTimeField(null=True, blank=True)
objects = SoftDeleteManager()
def delete(self):
self.deleted_at = now()
self.save()
5. ์ธ์ Soft Delete๋ฅผ ์ฌ์ฉํด์ผ ํ ๊น?
- ์ญ์ ๋ ๋ฐ์ดํฐ ๋ณต๊ตฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ (์: ๊ณ ๊ฐ ๊ณ์ ๋นํ์ฑํ, ๊ฒ์๋ฌผ ์จ๊น ๊ธฐ๋ฅ)
- ๋ฐ์ดํฐ ๊ฐ์ฌ ๋ฐ ์ถ์ ์ด ํ์ํ ๊ฒฝ์ฐ (์: ๋ก๊ทธ ๊ธฐ๋ก ์ ์ง)
- ์ฐ๊ด ๋ฐ์ดํฐ๊ฐ ๋ง์ Hard Delete ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ
ํ์ง๋ง, ๋ฐ์ดํฐ๊ฐ ๋๋ฌด ๋ง์ด ์์ด๋ฉด ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก ์ฃผ๊ธฐ์ ์ผ๋ก ์ ๋ฆฌํ๋ ์์ ์ด ํ์ํ๋ค.
6. Soft Delete ์ ๋ฆฌ
- ๋ฐ์ดํฐ๋ฅผ ๋ฌผ๋ฆฌ์ ์ผ๋ก ์ญ์ ํ์ง ์๊ณ , ๋ ผ๋ฆฌ์ ์ผ๋ก ์จ๊ธฐ๋ ๋ฐฉ์
- `is_deleted`(Boolean) ๋๋ `deleted_at`(ํ์์คํฌํ) ์ปฌ๋ผ์ ํ์ฉํ์ฌ ๊ตฌํ
- ๋ณต๊ตฌ๊ฐ ๊ฐ๋ฅํ๊ณ , ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํ ์ ์์
- ํ์ง๋ง ์ฟผ๋ฆฌ๊ฐ ๋ณต์กํด์ง๊ณ ์ฑ๋ฅ ์ต์ ํ๊ฐ ํ์ํ ์ ์์
์ญ์ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณต๊ตฌํด์ผ ํ ๊ฐ๋ฅ์ฑ์ด ์๋ค๋ฉด Soft Delete๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ข๋ค~
'AI ๐ค > Django โ๏ธ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[250310] WebSocket์ด๋? (1) | 2025.03.10 |
---|---|
[250306] update()์ save()์ ์ฐจ์ด (0) | 2025.03.06 |
[250219] Json Web Token์ ๋ํ์ฌ,,, (0) | 2025.02.19 |
[250217] ์ธ์ฆ(Authentication)๊ณผ ๊ถํ(Authorization) (0) | 2025.02.17 |
[250213] API ๋ช ์ธ์ ์์ฑ๋ฒ๊ณผ ํ์์ฑ์ ๋ํ์ฌ (5) | 2025.02.13 |