์ œ์ˆ˜๊ธฐ > django > table ๐Ÿ’ฅ๐Ÿ”ฅโœจ ์ค‘์š”

Eunbi Joยท2025๋…„ 1์›” 9์ผ
0

์ œ์ˆ˜๊ธฐ

๋ชฉ๋ก ๋ณด๊ธฐ
59/90
์ œ์ˆ˜๊ธฐ - ์ œ๋ฐœ ์ˆ˜์—…๋‚ด์šฉ์„ ๊ธฐ์–ตํ•ด๋ผ / ๋‹จ์ˆœ ์ˆ˜์—…์ •๋ฆฌ ์‹œ๋ฆฌ์ฆˆ

ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„

ํ…Œ์ด๋ธ”๊ณผ ํ…Œ์ด๋ธ”์˜ ๊ด€๊ณ„๊ฐ€ 1:N์ด๋“  N:N์ด๋“  ์ด๋Ÿฐ ๊ตฌ๋ถ„์ด ํ”„๋กœ์ ํŠธ ์„ค๊ณ„ํ•  ๋•Œ๋ถ€ํ„ฐ ํ•„์š”ํ•˜๋‹ค. ๋งค์šฐ ์ค‘์š”!!

์˜ˆ๋ฅผ ๋“ค์–ด ์ƒํ’ˆ์ •๋ณด๋ฅผ ๋‹ด์„ product ํ…Œ์ด๋ธ”์ด ํ•˜๋‚˜ ์žˆ๋‹ค๊ณ  ํ•˜์ž. ์ƒํ’ˆ ๋ฆฌ๋ทฐ๊ฐ€ ์จ์ง€๋Š” ํ…Œ์ด๋ธ”๋„ ์žˆ๋‹ค๋ฉด

  • product์™€ review์˜ ๊ด€๊ณ„๋Š” 1:N
  • product์™€ discount์™€๋Š” 1:1
  • product์™€ category์™€๋Š” N:M (๋ธŒ๋ฆฟ์ง€ ํ…Œ์ด๋ธ” ํ•„์š”. ๊ทผ๋ฐ ์ด๊ฑด ORM์ด ์•Œ์•„์„œ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋ธ์„ ๋”ฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š์•„๋„ ๋œ๋‹ค.)

์ด ํ…Œ์ด๋ธ”์„ ORM์— ๋ฐ˜์˜ํ•˜๋Š” ์• ๊ฐ€ Model์ด๋‹ค.

๋ชจ๋ธ์ด๋ผ๋ฉด, ํ„ฐ๋ฏธ๋„ shell์—์„œ python manage.py shell์„ ๊ผญ ํ•˜๊ณ  ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค.

ํ™˜๊ฒฝ๋งŒ๋“ค๊ธฐ

ํ๋ฆ„ ์„ค๋ช…
๋ฌด์กฐ๊ฑด ๋ชจ๋ธ ํด๋ž˜์Šค๋ถ€ํ„ฐ ๋จผ์ € ์ž‘์„ฑ
๊ทธ ๋‹ค์Œ์— ์—ฐ๋™๋œ DB์— migrationํ•˜๊ณ 
post ์•ฑ ์„ค์น˜ํ•˜๊ณ  ๊ธฐ๋ณธ CRUD ํ…Œ์ŠคํŠธ ํ•ด๋ดค๋‹ค.

Django ORM MySQL ์—ฐ๋™ํ•˜๊ธฐ

  • settings.py databases ๋ฐ”๊ฟจ์Œ

๋ชจ๋ธ ํด๋ž˜์Šค ์ž‘์„ฑํ•˜๊ธฐ

class Product(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, null=True) # blank ๋นˆ๋ฌธ์ž์—ด ํ—ˆ์šฉ์—ฌ๋ถ€
    price = models.PositiveIntegerField()
    stock = models.PositiveIntegerField()
    available = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name


# 1:1 ๊ด€๊ณ„
class Discount(models.Model):
    product = models.OneToOneField(Product, on_delete=models.CASCADE)
    discount_percentage = models.FloatField()
    start_date = models.DateTimeField()
    end_date = models.DateTimeField()

    def __str__(self):
        return f'{self.product.name} {self.discount_percentage * 100}% discount'


# 1:N ๊ด€๊ณ„
class Review(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    user_id = models.PositiveIntegerField(blank=True, null=True)
    rating = models.PositiveIntegerField(default=1, help_text="ํ‰์  1 ~ 5")
    comment = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'{self.product.name} ์ƒํ’ˆ๋ฆฌ๋ทฐ by {self.user_id}'


# N:M ๊ด€๊ณ„
class Category(models.Model):
    name = models.CharField(max_length=100, unique=True) # UQ ์ œ์•ฝ์กฐ๊ฑด ์ถ”๊ฐ€
    products = models.ManyToManyField(Product, blank=True)

    def __str__(self):
        return self.name

๋ชจ๋ธ ํด๋ž˜์Šค ์‹ค์ œ DB์— Migrationํ•˜๊ธฐ

  1. SQL ๊ฒฝ๋กœ์— product.sql ์ œ์ž‘
  2. ๋‚ด์šฉ ์ฑ„์›Œ๋„ฃ๊ธฐ
  3. shell ๋ง๊ณ  ๋”ฐ๋กœ ํ„ฐ๋ฏธ๋„ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค์–ด์„œ migration ๋ช…๋ น์–ด 2๊ฐœ ์‹คํ–‰ํ•˜๊ธฐ.
  • python manage.py makemigrations product
  • python manage.py migrate product

๋ธŒ๋ฆฟ์ง€ ํ…Œ์ด๋ธ”์ด ์ž๋™์œผ๋กœ ํ˜•์„ฑ๋๋‹ค.

1:N (Product:Review)

  • from product.models import Product, Discount, Review, Category
    ํ•ด๋†“๊ณ  ์‹œ์ž‘ํ•˜๊ธฐ

๋ฆฌ๋ทฐ์กฐํšŒ > filter ์“ฐ๊ธฐ

Review.objects.filter(product_id=1)
product_id๊ฐ€ 1์ธ ์—ด์„ ์กฐํšŒํ•ด์„œ review๋ฅผ ํ•„ํ„ฐํ•ด์„œ ๋ณด๊ฒ ๋‹ค. ์—ฌ๊ธฐ์„œ object๋Š” Django์˜ ORM (Object-Relational Mapping)์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” ๋งค๋‹ˆ์ €(manager)๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ฆ‰, ๋ชจ๋ธ ํด๋ž˜์Šค(Review)์— ์—ฐ๊ฒฐ๋œ ๊ธฐ๋ณธ ๋งค๋‹ˆ์ € ์—ญํ• ์„ ํ•œ๋‹ค.

๐Ÿ’ฅ filter ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์“ฐ๋ ค๋ฉด ํ•ญ์ƒ object ์ ๊ณ  ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋Š” ๊ฑด๊ฐ€? -> ๊ทธ๋ ‡๋‹ค.

๋ณ€์ˆ˜์— ๋ฆฌ๋ทฐ๋‚ด์šฉ์„ ๋‹ด๊ณ , ๋‹ค๋ฅธ ๋‚ด์šฉ๋“ค๊ณผ ๊ฐ™์ด ๋ฐ˜๋ณต๋ฌธ ๋Œ๋ ค์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

โœ๏ธ์ด๊ฑฐ ๋‹ค ์“ฐ๊ณ  Enter ํ•œ๋ฒˆ ๋” ์ณ์ค˜์•ผ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค.

๋ฆฌ๋ทฐ์กฐํšŒ > get, filter, set, set_all ์“ฐ๊ธฐ

๐Ÿ’ฅ ์™œ prodcut=product์ธ๊ฑฐ์ง€..? -> ํ•„๋“œ / ๊ฐ์ฒด๋‹ค. ์›๋ž˜๋Š” FK?๊ฐ€ ํ•„๋“œ์—์„œ id๊ฐ€ ๋˜๋Š”๋ฐ ์—ฌ๊ธฐ์„  ์ž๋™์œผ๋กœ ๋ผ์„œ ์ด๋ ‡๊ฒŒ ๋œ๋‹ค..?

ํ‰์ ์กฐํšŒ > aggregate

  • from django.db.models import Sum, Avg, Count, Max, Min
    ํ•ด๋†“๊ณ  ์‹œ์ž‘ํ•˜๊ธฐ

set.aggregate

ํ‰์ ์กฐํšŒ > annotate

annotate : ํŠน์ •์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, ์ง‘๊ณ„

์ง€๋‚œ 1์ฃผ์ผ๊ฐ„์˜ ๋ฆฌ๋ทฐ ์กฐํšŒ

from datetime import datetime, timedelta ํ•ด๋†“๊ณ  ์‹œ์ž‘

weeks๋Š” 1์ธ๋ฐ days๋Š” ์™œ 30์ธ๊ฑฐ์ง€๐Ÿ’ฅ -> ๋‹จ์œ„๋‹ค. days=30์€ 30์ผ ๋‹จ์œ„๋‹ค. weeks=1์€ ์ผ์ฃผ์ผ์ด๋‹ค. timedelta ์ƒ์„ฑ์ž์˜ ํŒŒ๋ผ๋ฏธํ„ฐ

1:1 Product(1)-Discount(1) / OneToOneField

product.discount๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” discount
1:1 ๊ด€๊ณ„

n๊ฐœ๊ฐ€ ๋‚˜์™€์„œ ์—๋Ÿฌ

product์— discount ์†์„ฑ ์—†์–ด์„œ ์˜ค๋ฅ˜

์†์„ฑ์ด ์žˆ๋Š”์ง€ ์ฐพ์•„๋ณด๊ณ  ์ง„ํ–‰ํ•ด์•ผ ํ•จ

์˜ค๋ฅ˜ ์ˆ˜์ • *100 ์ง€์šฐ๊ณ  ์ง„ํ–‰

ํ• ์ธ ์ค‘์ธ ๋ชจ๋“  ์ƒํ’ˆ ๊ฐ€์ ธ์˜ค๊ธฐ

  • ์˜ค๋Š˜ ํ• ์ธ์ค‘์ธ ์ƒํ’ˆ์„ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ์กฐ๊ฑด์„ ์–ด๋–ป๊ฒŒ ์งœ์•ผํ• ๊นŒ? ๋‘ ๊ฐœ์˜ ์กฐ๊ฑด์ด ํ•„์š”ํ•˜๋‹ค.
    start_date <= now() and end_date >= now();
    Discount ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ์ฐพ์•„๋‚ธ๋‹ค.
  • ์—ฌ๋Ÿฌ ์ •๋ณด ํ•œ๋ฒˆ์— ๊ฐ™์ด ๋ณด๊ธฐ
    ์—๋Ÿฌ

    ํ•ด๊ฒฐ -> tab์ด ์—†์—ˆ๋‹ค.

์ œํ’ˆ+ํ• ์ธ์ •๋ณด

products = Product.objects.all() ์ด๊ฑด product๋งŒ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์™œ discount๋Š” ์•ˆ ๋‚˜์˜ฌ๊นŒ? ์ด๋Ÿฐ ๊ฑธ lazy query ๋ผ๊ณ  ํ•˜๋Š”๋ฐ

lazy query : ์‹ค์ œ๋กœ discount์— ๊ฐ€์„œ ์กฐํšŒ๋ฅผ ํ•ด์•ผ ํ• ํ…๋ฐ ์ง„์งœ ํ•„์š”ํ•  ๋•Œํ•œ๋‹ค. ์‹ค์ œ ๊ทธ ์†์„ฑ์— ์ ‘๊ทผํ•  ๋•Œ.

์ผ๋‹จ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ œํ’ˆ+ํ• ์ธ์ •๋ณด๋Š” ๋‚˜์˜จ๋‹ค.

์ตœ๊ทผ 10๊ฐœ ์ฟผ๋ฆฌ๋ฅผ ์กฐํšŒํ•ด๋ณด๋ฉด
๊ณ„์† ๋ฐ˜๋ณต๋˜๋ฉด์„œ ๋‚˜์˜จ๋‹ค.

๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ฟผ๋ฆฌ๊ฐ€ ๋งŽ์ด ๋‚ ์•„๊ฐ€๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•œ๋ฐฉ์— ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

๊ด€๋ จ๋œ ๋ชจ๋ธ์˜ ์ •๋ณด๊นŒ์ง€ ํ•œ๋ฒˆ์— ์กฐํšŒํ•˜๊ธฐ

N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ๊ฐ€๋Šฅํ•œ ์กฐ์ธ์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ

discount์™€ ์—ฐ๊ฒฐ๋œ ๊ฒƒ๋“ค์„ ๋ฏธ๋ฆฌ ์ข€ ์กฐํšŒํ•ด ์ฃผ์„ธ์š”. ๋ผ๋Š” ๋œป.
prefetch_related๋ฅผ ์“ธ ๋•Œ ์ด๋ฏธ ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ”๋‹ค.

์•„๋ž˜ ๋ฐ˜๋ณต๋ฌธ์ด ์•„๋‹ˆ๋ผ, ์œ„์—์„œ ์ด๋ฏธ ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ”๊ธฐ ๋•Œ๋ฌธ์—, ์„ฑ๋Šฅ์ ์œผ๋กœ ์šฐ์ˆ˜ํ•˜๋‹ค.

์ฟผ๋ฆฌ ์กฐํšŒ (์กฐ์ธ๋œ ๊ฑธ๋กœ ์•ˆ ๋‚˜์™€์„œ ๋‚˜์ค‘์— ๋‹ค์‹œ ์•Œ๋ ค์ฃผ์‹ ๋‹ค๊ณ  ํ•˜์‹ฌ)

N:M (Product(N)-Category(M))

N:M ๊ด€๊ณ„ ํ™•์ธํ•˜๊ธฐ

  • ํ•œ๊ฐœ์˜ ์ƒํ’ˆ์ด ์—ฌ๋Ÿฌ๊ฐœ์˜ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ฐ€์ง„๋‹ค.
  • ํ•˜๋‚˜์˜ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ์ƒํ’ˆ์— ์‚ฌ์šฉ๋œ๋‹ค.
    ์œ„ ๋ง์ด ๋œ๋‹ค๋ฉด, n:m ๊ด€๊ณ„๋‹ค.

Category์™€ Product์˜ ๊ด€๊ณ„์—์„œ models.ManyToManyField๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค.
n:m์—์„œ products ์ž๋ฆฌ์—๋Š” ๋ณดํ†ต ๋ณต์ˆ˜ํ˜•์„ ์“ด๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ํ•˜๋‚˜ ์žˆ๋Š” id=1 ์ƒํ’ˆ๊ณผ
์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ์žˆ๋Š” id=9 ์ƒํ’ˆ

๊ฐ€์ „์— ํ•ด๋‹นํ•˜๋Š” ์ƒํ’ˆ์„ ์กฐํšŒํ•ด๋ณด์ž

๐Ÿ’ฅ์กฐํšŒํ•  ๋•Œ ๋ชจ๋ธ์—์„œ ์คฌ๋˜ products๋ฅผ ์จ์ค˜์•ผ ํ•จ. ์ด์œ ๋Š” ์ž˜ ๋ชจ๋ฅด๊ฒ ์Œ. ์นดํ…Œ๊ณ ๋ฆฌ์—์„œ ๋ณด๋Š” ๊ฒŒ products์—ฌ์„œ ๊ทธ๋ ‡๋‹ค..? -> categort์— prodcuts:ManyToManyField๋ฅผ ์ฐธ์กฐํ•œ๊ฑฐ๊ณ  Product์—์„œ๋Š” category set์„ ๋ณด๋‚ธ๋‹ค. ์กฐํšŒ๋„ Category์—์„œ ํ•˜๋Š” ๊ฑฐ๋ผ์„œ products๋ผ๊ณ  ์“ฐ๋Š” ๊ฑฐ๋‹ค.

์ƒํ’ˆ์ด ์—†๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ

์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์—†๋Š” ์ƒํ’ˆ ์กฐํšŒ

์—ฐ๊ด€๊ด€๊ณ„
1:N > N์ชฝ ๋ชจ๋ธ์— foreignKey ํ•„๋“œ ์ง€์ •
1:1 > 1์ชฝ ๋ชจ๋ธ์— OneToOneField ์ง€์ •
N:M > M์ชฝ ๋ชจ๋ธ์— ๊ฐ€์„œ ManyToNanyField ์ง€์ •

์—ญ๋ฐฉํ–ฅ ์ฐธ์กฐ ๋„ฃ๊ธฐ

์—ญ๋ฐฉํ–ฅ ์ฐธ์กฐ ์ด๋ฆ„์€ related_name= ์œผ๋กœ ๋„ฃ๋Š”๋‹ค.

๋ชจ๋ธ์— ๊ฐ€์„œ ๋„ฃ์–ด์ฃผ์ž.

์›๋ž˜๋Š” ๊ธฐ๋ณธ๊ฐ’์ด review_set์ด์ง€๋งŒ ํ”„๋Ÿฌ๋•ํŠธ๊ฐ€ ๋ฆฌ๋ทฐ ์ฐธ์กฐํ•  ๋•Œ ์“ฐ๋Š” ๊ฑด๋ฐ, ๋ณต์ˆ˜ํ˜•์œผ๋กœ ์“ฐ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

์—ฌ๊ธฐ๋„ ์›๋ž˜ category_set์ธ๋ฐ ๋ณต์ˆ˜ํ˜•์œผ๋กœ ์จ์ฃผ์ž.

aggregate ํ•จ์ˆ˜๋ฅผ ์“ฐ๋ฉด ์ „์ฒด๋ฅผ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์œผ๋กœ ๊ฐ„์ฃผํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฑฐ๋‹ค.
๊ทธ๋ž˜์„œ ์ „์ฒด ์ƒํ’ˆ์ด ๋ช‡ ๊ฑด์ด์•ผ?

์ฟผ๋ฆฌ select cont(*) from product์™€ ๋˜‘๊ฐ™๋‹ค.
๐Ÿ’ฅcount๊ฐ€ ๋ฐ˜ํ™˜๋  ๋”•์…”๋„ˆ๋ฆฌ์˜ ํ‚ค๊ฐ’์ด ๋œ๋‹ค?

์ƒํ’ˆ์˜ ํ‰๊ท , ์ตœ๋Œ€๊ฐ’, ์ตœ์†Œ๊ฐ’ ์กฐํšŒ ๊ฐ€๋Šฅ

๊ฐ€์ „ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋ชจ๋“  ์ œํ’ˆ์˜ ํ‰๊ท  ๊ธˆ์•ก

aggregate๋ฅผ ์“ฐ๋ฉด ๋œ๋‹ค. ์ „์ฒด๋ฅผ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์–ด์ฃผ๋‹ˆ๊นŒ.

๋‘˜ ๋‹ค ๋˜‘๊ฐ™๋‹ค.

group by ํ‰๋‚ด๋‚ด๊ธฐ (value + annotate)

groupby์— ํ•ด๋‹นํ•˜๋Š” ๊ฑด ์—†๋‹ค. value๋ผ๊ณ  ์žˆ๋Š”๋ฐ ์ด๊ฑธ๋กœ ํ•œ๋ฒˆ ํ•ด๋ณด์ž.

annotate : ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•˜๋Š” ์• .

์›ํ•˜๋Š” ์ปฌ๋Ÿผ๋งŒ ์ถ”๋ ค๋‚ด์„œ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค.
๋ฆฌ๋ทฐ ํ•˜๋‚˜ ํ•˜๋‚˜์—์„œ ์›ํ•˜๋Š” ์š”์†Œ๋งŒ ์ถ”๋ ค๋‚ด์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋ฆฌ๋ทฐ์ธ๋ฐ product id๋งŒ ์ ํ˜€์žˆ๊ณ  ๊ฐ™์€ ์• ๋“ค๋ผ๋ฆฌ ๋ฌถ์–ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ œํ’ˆ๋ณ„ ๋ฆฌ๋ทฐ๊ฐœ์ˆ˜ ๊ฐ™์€ ๊ฑธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€๊ธˆ ๋ฆฌ๋ทฐ์—์„œ ์ƒํ’ˆ๋ณ„๋กœ ์นด์šดํŠธํ–ˆ์ง€๋งŒ, ์ด๊ฑธ product์— ๊ฐ€์„œ id๋งŒ ๋ฝ‘๊ณ , annotate๋กœ ๋ฆฌ๋ทฐ์—์„œ ๋ฆฌ๋ทฐ ์นด์šดํŠธ๋ฅผ ๋ถˆ๋Ÿฌ๋‚ด๋ฉด ๋œ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ œํ’ˆ์ˆ˜

๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ์ž˜ ๋ณด์ด๊ฒŒ ํ•˜๊ธฐ

0๊ฐœ์˜ ๋Œ“๊ธ€