๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“๐Ÿ’ช/Django

Model , Shell

by ์ˆ˜์จ”์•™ 2022. 9. 27.

 

 

Model ์ž‘์„ฑํ•˜๊ธฐ

 

1. views.py์˜ ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ณ  ํ•„๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ• ์ง€ ์ƒ๊ฐํ•ด๋ณธ๋‹ค.

 

 

2. models.py ์ž‘์„ฑ

๋ชจ๋“  ๋ชจ๋ธ์€ ํด๋ž˜์Šค๋กœ ์ž‘์„ฑ๋˜๊ณ , ์žฅ๊ณ ์—์„œ ์ œ๊ณตํ•˜๋Š” model์„ ๋ฐ›์•„์™€์•ผํ•œ๋‹ค.

from pydoc import describe
from django.db import models

class Menu(models.Model): # ์ƒ์†
    name = models.CharField(max_length=50) # charfield๋Š” ์ €์žฅํ•  ์ตœ๋Œ€๊ธธ์ด๊ฐ€ ํ•„์ˆ˜์ธ์ˆ˜
    description = models.CharField(max_length=100)
    price = models.IntegerField()
    img_path = models.CharField(max_length=255)

    def __str__(self):
        return self.name

 

model field ์ •๋ฆฌ

๋”๋ณด๊ธฐ

ํ•„๋“œ(Field)

ํ•„๋“œ(Field)๋Š” ๋ฐ์ดํ„ฐ ํ…Œ์ด๋ธ”์—์„œ์˜ ์—ด(column), ์ฆ‰ ๋ฐ์ดํ„ฐ์˜ ์†์„ฑ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

CharField

class CharField(max_length=None)

์ œํ•œ๋œ ๊ธธ์ด์˜ ๋ฌธ์ž์—ด์„ ์œ„ํ•œ ํ•„๋“œ์ž…๋‹ˆ๋‹ค.

  • max_length ํ•„์ˆ˜ ์ธ์ˆ˜์ด๋ฉฐ ์ž…๋ ฅํ•  ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

IntegerField

class IntegerField()

์ •์ˆ˜ ๊ฐ’์„ ์œ„ํ•œ ํ•„๋“œ์ด๋ฉฐ -2147483648 ๋ถ€ํ„ฐ 2147483647 ๋ฒ”์œ„๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

BooleanField

class BooleanField()

Boolean ๊ฐ’์„ ์œ„ํ•œ ํ•„๋“œ ์ž…๋‹ˆ๋‹ค.

DateField

class DateField(auto_now=False, auto_now_add=False)

DateField๋Š” ํŒŒ์ด์ฌ์˜ datetime.date ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ํ‘œ์‹œ๋˜๋Š” ๋‚ ์งœ ํ•„๋“œ์ž…๋‹ˆ๋‹ค.

  • auto_now true๋กœ ์„ค์ •๋˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ(save) ๋  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ํ•„๋“œ ๊ฐ’์„ ์ง€๊ธˆ์œผ๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. '๋งˆ์ง€๋ง‰ ์ˆ˜์ • ์‹œ๊ฐ„' ๊ฐ™์€ ํ•ญ๋ชฉ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹๊ฒ ์ฃ ?
  • auto_now_add ๋ชจ๋ธ์ด ์ฒ˜์Œ ์ƒ์„ฑ๋  ๋•Œ ํ•œ ๋ฒˆ, ์ž๋™์œผ๋กœ ํ•„๋“œ ๊ฐ’์„ ์ง€๊ธˆ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. '์ƒ์„ฑ๋œ ์‹œ๊ฐ„'์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

DateTimeField

class DateTimeField(auto_now=False, auto_now_add=False)

ํŒŒ์ด์ฌ์˜ datetime.datetime ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ํ‘œ์‹œ๋˜๋Š” ๋‚ ์งœ ํ•„๋“œ ์ž…๋‹ˆ๋‹ค. DateField์™€ ์ธ์ˆ˜ ์˜ต์…˜์€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

EmailField

class EmailField(max_length=254)

CharField์˜ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ๋ฌธ์ž์—ด์ด ์ด์šฉ ๊ฐ€๋Šฅํ•œ ์ด๋ฉ”์ผ ์ฃผ์†Œ์ธ์ง€ EmailValidator๋ฅผ ํ†ตํ•ด ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. EmailValidator์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ์•„๋ž˜ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. (https://docs.djangoproject.com/en/3.1/ref/validators/#django.core.validators.EmailValidator)

FileField

class FileField(upload_to=None, max_length=100)

ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ์œ„ํ•œ ํ•„๋“œ ์ž…๋‹ˆ๋‹ค.

ImageField

class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100)

FileField๋ฅผ ์ƒ์†ํ•˜์—ฌ ๊ตฌํ˜„๋˜๋Š” ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ์œ„ํ•œ ํ•„๋“œ์ด๋ฉฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ตœ๋Œ€ ๊ธธ์ด๊ฐ€ 100์ธ ๋ฌธ์ž์—ด ํ˜•์‹์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ๋‚˜์™”๋˜ FileField์—์„œ ์—…๋กœ๋“œ๋œ ํŒŒ์ผ์ด ์ •์ƒ์ ์ธ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์ด ์ถ”๊ฐ€๋œ ํ•„๋“œ๋กœ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ Pillow ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์ˆ˜์ ์œผ๋กœ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ ๋’ค์—์„œ ํ•จ๊ป˜ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

  • height_field & width_field ๊ฐ์ฒด๊ฐ€ ์ €์žฅ ๋  ๋•Œ ์ด๋ฏธ์ง€์˜ ๋†’์ด์™€ ๋„ˆ๋น„๊ฐ’์ด ์ž๋™์œผ๋กœ ์ฑ„์›Œ ์ง‘๋‹ˆ๋‹ค.

์ด ๋ฐ–์—๋„ IP ์ฃผ์†Œ๋ฅผ ์ฒดํฌ๋ฅผ ํ•˜๋Š” GenericIPAddressField, JSON ํŒŒ์ผ์„ ์œ„ํ•œ JSONField (django 3.1 ๋ฒ„์ „ ์ด์ƒ๋ถ€ํ„ฐ ์ง€์›) ํŠน์ • ํด๋”์˜ ํŒŒ์ผ ํŒจ์Šค๋ฅผ ํ‘œํ˜„ํ•˜๋Š” FilePathField, URL์„ ์œ„ํ•œ URLField ๋“ฑ ๋‹ค์–‘ํ•œ ํ•„๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. ( https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.Field.default )

์˜ต์…˜(Option)

์•„๋ž˜ ์˜ต์…˜์€ ๋ชจ๋“  ํ•„๋“œ ํƒ€์ž…์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์„ ํƒ์ ์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

null

Field.null

๊ธฐ๋ณธ ๊ฐ’์€ False์ด๋ฉฐ Null ๊ฐ’ ํ—ˆ์šฉ ์—ฌ๋ถ€๋ฅผ ์„ ํƒ ํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ด null ์˜ต์…˜์„ ์ ์šฉํ•  ํ•„๋“œ๊ฐ€ ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ ํ•„๋“œ (Char, Text)์ผ ๊ฒฝ์šฐ์—๋Š” ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ ' ' (๋นˆ ๋ฌธ์ž์—ด)๊ณผ Null ๋ชจ๋‘ ํ•ด๋‹น ํ•„๋“œ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š” ๊ฐ’์€ ํ•˜๋‚˜์—ฌ์•ผ ํ•˜๋ฏ€๋กœ Django๋Š” ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ ํ•„๋“œ๊ฐ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Œ์„ ํ‘œ์‹œํ•  ๋•Œ๋Š” ' '(๋นˆ ๋ฌธ์ž์—ด)์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ถŒ์žฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

blank

Field.blank

๊ธฐ๋ณธ ๊ฐ’์€ False์ด๋ฉฐ True๋กœ ์„ค์ •ํ•œ ๊ฒฝ์šฐ ํ•„๋“œ ๊ฐ’์„ ๋นˆ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด null๊ณผ blank์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡ ์ผ๊นŒ์š”? null์€ ์˜จ์ „ํžˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ด€๋ จ๋œ ์‚ฌํ•ญ์ด๊ณ  blank๋Š” ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ ๊ด€๋ จ๋œ ์˜ต์…˜์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด blank๊ฐ€ True๋ผ๋ฉด ํ•ด๋‹น ํ•„๋“œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•˜์ง€ ์•Š์•„๋„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

default

Field.default

ํ•„๋“œ์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ์˜ต์…˜์œผ๋กœ ๊ฐ’ ๋˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

db_column

Field.db_column

ํ•ด๋‹น ํ•„๋“œ์— ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์†์„ฑ ๋ช…์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ ํ•„๋“œ์˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋” ๋งŽ์€ ํ•„๋“œ์™€ ์˜ต์…˜์— ๋Œ€ํ•ด ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜ django ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.Field.default

 

 

3. ๋ชจ๋ธ์ด ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋˜๋ฉด ์žฅ๊ณ ํ•œํ…Œ ์•Œ๋ ค์ค˜์•ผํ•œ๋‹ค.

python manage.py makemigrations # migrations ๋งŒ๋“ค๊ธฐ

python manage.py migrate # migrations ์ ์šฉ์‹œํ‚ค๊ธฐ

python manage.py showmigrations # ํ˜„์žฌ ์ƒ์„ฑ๋˜์–ด ์žˆ๋Š” migration ๋ชฉ๋ก๋ณด๊ธฐ [X] ๋ฐ˜์˜๋œ๊ฒƒ

python manage.py sqlmigrate ์•ฑ์ด๋ฆ„ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๋ฒˆํ˜ธ # migration์ด orm์„ ํ†ตํ•ด์„œ ์–ด๋–ป๊ฒŒ sql๋กœ ๋ณ€ํ™˜๋˜์—ˆ๋Š”์ง€ ํ™•์ธ

 

 

 

shell ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ, ์กฐํšŒ, ์ˆ˜์ •, ์‚ญ์ œํ•˜๊ธฐ

 

1) shell ์‹คํ–‰

python manage.py shell

 

2) ์•ฑ ์•ˆ์— ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

# foods ์•ฑ ์•ˆ์˜ models์—์„œ Menu ๋ชจ๋ธ์„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
from foods.models import Menu

 

3) ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ

# {model๋ช…}.objects.create({ํ•„๋“œ๋ช…}={๊ฐ’})
Menu.objects.create(name="์ฝ”๋”ฉ์— ๋น ์ง„ ๋‹ญ",
... description="์ฃผ๋จธ๋‹ˆ๊ฐ€ ๊ฐ€๋ฒผ์šด ๋‹น์‹ ์˜ ๋งˆ์Œ๊นŒ์ง€ ์ƒ๊ฐํ•œ ๊ฐ€๊ฒฉ",
... price = 10000,
... img_path = "foods/images/chicken.jpg")

# <Menu:์ฝ”๋”ฉ์— ๋น ์ง„ ๋‹ญ>

 

4) ๋ฐ์ดํ„ฐ ์กฐํšŒํ•˜๊ธฐ

# ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์กฐํšŒํ•˜๊ธฐ
Menu.objects.all()
#<QuerySet [<Menu: ์ฝ”๋”ฉ์— ๋น ์ง„ ๋‹ญ>]>


# ์„ธ๋ถ€ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์กฐํšŒํ•˜๊ธฐ
Menu.objects.all().values()

"""
<QuerySet [{'id': 1, 'name': '์ฝ”๋”ฉ์— ๋น ์ง„ ๋‹ญ', 'description': '์ฃผ๋จธ๋‹ˆ๊ฐ€ ๊ฐ€๋ฒผ์šด ๋‹น์‹ ์˜ ๋งˆ์Œ๊นŒ
์ง€ ์ƒ๊ฐํ•œ ๊ฐ€๊ฒฉ', 'price': 10000, 'img_path': 'foods/images/chicken.jpg'}, {'id': 2, 'name': '๋„ˆ๋Š” ๋‚ด๊ฒŒ ๋น ๋‚˜๋‚˜', 'description': '๋ฐ”๋‚˜๋‚˜ ์•ˆ๋ฐ”๋‚˜๋‚˜ ๋ฐ”๋‚˜๋‚˜', 'price': 2000, 'img_path': 'foods/images/banana.jpg'}, {'id': 3, 'name': '์ฝ”๋ฐ๋ฆฌ์•„', 'description': '์ฐธ๊นจ๋นต ์œ„์— ์ˆœ์‡ ๊ณ ๊ธฐ ํŒจํ‹ฐ
 ์„ธ์žฅ', 'price': 8000, 'img_path': 'foods/images/burger.jpg'}]>
"""

# ์กฐํšŒํ•˜๊ณ  ์‹ถ์€ ํ•„๋“œ๋งŒ ์กฐํšŒํ•˜๊ธฐ
Menu.objects.all().values('price')
# <QuerySet [{'price':10000},{'price':2000},{'price':8000}]>


# ๊ฐ€๊ฒฉ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•ด์„œ ์กฐํšŒํ•˜๊ธฐ
Menu.objects.order_by('price')


# ์Œ์‹ ์ด๋ฆ„ ์ค‘์— ์ฝ” ๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ๋“ค์–ด๊ฐ„ ๋ชจ๋“  ์Œ์‹ ์กฐํšŒ
Menu.objects.filter(name__contains="์ฝ”")
# <QuerySet [<Menu: ์ฝ”๋”ฉ์— ๋น ์ง„ ๋‹ญ>, <Menu: ์ฝ”๋ฐ๋ฆฌ์•„>]>


# 2000์› ๋ถ€ํ„ฐ 10000์› ์‚ฌ์ด์˜ ์Œ์‹ ์กฐํšŒ
Menu.objects.filter(price__range(2000,10000))

 

5) ๋ฐ์ดํ„ฐ ์ˆ˜์ •

>>> data = Menu.objects.get(id=1) # id=1๋ฒˆ์งธ๋ฅผ data์— ์ €์žฅ
>>> data # data ์ถœ๋ ฅ
<Menu: ์ฝ”๋”ฉ์— ๋น ์ง„ ๋‹ญ>
>>> data.name = "์ฝ”๋น ๋‹ญ" # ๋ณ€๊ฒฝ
>>> data  
<Menu: ์ฝ”๋น ๋‹ญ>
>>> data.save() # ์ €์žฅ 
>>> Menu.objects.all()
<QuerySet [<Menu: ์ฝ”๋น ๋‹ญ>, <Menu: ๋„ˆ๋Š” ๋‚ด๊ฒŒ ๋น ๋‚˜๋‚˜>, <Menu: ์ฝ”๋ฐ๋ฆฌ์•„>]>

 

6) ๋ฐ์ดํ„ฐ ์‚ญ์ œ

>>> data = Menu.objects.get(id=3) # id=3๋ฒˆ์งธ ๊ฐ’์„ data์— ๋„ฃ๊ณ 
>>> data
<Menu: ์ฝ”๋ฐ๋ฆฌ์•„>
>>> data.delete() # ์‚ญ์ œ
(1, {'foods.Menu': 1})
>>> Menu.objects.all()
<QuerySet [<Menu: ์ฝ”๋น ๋‹ญ>, <Menu: ๋„ˆ๋Š” ๋‚ด๊ฒŒ ๋น ๋‚˜๋‚˜>]>
>>>

 

7) ์ข…๋ฃŒ

exit()

 

 

 

Model ์ ์šฉํ•˜๊ธฐ

 

ํ•˜๋“œ์ฝ”๋”ฉ : ์†Œ์Šค ์ฝ”๋“œ ์•ˆ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ง์ ‘ ์ž…๋ ฅ๋˜์–ด ์žˆ๋Š” ์ฝ”๋”ฉ ํ˜•ํƒœ, ๋ฐ์ดํ„ฐ ์œ ์‹ค ์œ„ํ—˜ & ์œ ์ง€๋ณด์ˆ˜ ์–ด๋ ค์›€

ํ•˜๋“œ์ฝ”๋”ฉ์„ ๋ฐ”๊ฟ”์ฃผ์ž

index ํ…œํ”Œ๋ฆฟ์— ์žˆ๋Š” ํ•˜๋“œ์ฝ”๋”ฉ์„ view์—์„œ ๋ชจ๋‘ ๋„˜๊ฒจ์ฃผ๋„๋ก ๋งŒ๋“ค๊ณ  index ๋ทฐ๋Š” ๋ชจ๋ธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•˜์ž

 

1. foods/views.py

index์—์„œ ๋ชจ๋“  ๋ฉ”๋‰ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ๋ถ€ํ„ฐ ๊ฐ€์ ธ์˜ค์ž

def index(request):
    context = dict()
    today = datetime.today().date()
    menus = Menu.objects.all()
    context["date"] = today
    context["menus"] = menus
    return render(request, 'foods/index.html', context=context)

 

2. index.html ์ˆ˜์ •

{% for menu in menus %}

{% endfor %} ์‚ฌ์šฉํ•˜์ž

    {% for menu in menus %}

        <div class="food">
                <img src={% get_static_prefix %}{{menu.img_path}} width="300px" height="200px" />
                <div class="info">
                    <h3>{{menu.name}}</h3>
                    <P>{{menu.description}}</p>
                    <a href="#">๋ฉ”๋‰ด ๋ณด๊ธฐ</a>
                </div>
            </div>

    {% endfor %}

 

 

 

 

 

 

728x90

๋Œ“๊ธ€