1. Django Tutorial(Airbnb) - Custom Admin Site

ID์งฑ์žฌยท2021๋…„ 7์›” 28์ผ
1

Django

๋ชฉ๋ก ๋ณด๊ธฐ
10/43
post-thumbnail

๐ŸŒˆ Custom Admin Site

๐Ÿ”ฅ Admin Site์— Model ๋“ฑ๋ก ๋ฐฉ๋ฒ•

๐Ÿ”ฅ Django์˜ Admin Panel ํ™•์žฅ์‹œํ‚ค๊ธฐ

๐Ÿ”ฅ Admin Panel Option

๐Ÿ”ฅ Model์˜ ๋งค์„œ๋“œ๋ฅผ admin์—์„œ ํ™œ์šฉํ•˜๊ธฐ

๐Ÿ”ฅ Timezone Utils ์‚ฌ์šฉํ•˜๊ธฐ

๐Ÿ”ฅ Save Method ์˜ค๋ฒ„๋ผ์ด๋”ฉ


1. Admin Site์— Model ๋“ฑ๋ก ๋ฐฉ๋ฒ•

  • Admin Site์— Model์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜ 2๊ฐ€์ง€๊ฐ€ ๋ชจ๋‘ ๊ฐ€๋Šฅํ•ด์š”. ๋‘ ๋ฐฉ๋ฒ• ๋ชจ๋‘ Model์„ import ํ•˜๋Š”๊ฑด ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

1) ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(@) ์‚ฌ์šฉ

  • ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด Model์„ ๋“ฑ๋กํ•˜๋ฉด ๋ฐ”๋กœ ์•„๋ž˜ class๋ฅผ ์ž๋™์œผ๋กœ ์ฐธ์กฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค admin class์ธ์ง€ ๋ช…์‹œํ•  ํ•„์š”๊ฐ€ ์—†์–ด์š”.
    • ๐Ÿ”Ž @admin.register(Model Class)
from django.contrib import admin
from . import models
@admin.register(models.User)
class CustomUserAdmin(admin.ModelAdmin):
    pass

2) admin.site.register ์‚ฌ์šฉ

  • admin.site.register๋ฅผ ์ด์šฉํ•˜๋ฉด ์–ด๋–ค admin class๋ฅผ ๋“ฑ๋กํ•˜๋Š”์ง€ ๋ชจ๋ธ๊ณผ ํ•จ๊ป˜ ๋ช…์‹œํ•ด์•ผํ•ด์š”.
    • ๐Ÿ”Ž admin.site.register(Model Class, Admin Class)
from django.contrib import admin
from . import models
class CustomUserAdmin(admin.ModelAdmin):
    pass
admin.site.register(models.User, CustomUserAdmin)

2. Django์˜ Admin Panel ํ™•์žฅ์‹œํ‚ค๊ธฐ

  • Django์˜ User ๋ชจ๋ธ์„ AbstractUser๋ฅผ ํ†ตํ•ด ํ™•์žฅ์‹œ์ผฐ๋‹ค๋ฉด Admin Panel ๋˜ํ•œ ๊ธฐ์กด Django๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ admin์„ ์ƒ์† ๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”!

1) Django์˜ User Admin Panel ์ƒ์† ๋ฐ›๊ธฐ

  • Django์˜ Admin ๊ฐ€์ ธ์˜ค๊ธฐ
    • ๐Ÿ”Ž from django.contrib.auth.admin import UserAdmin
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin # ๐Ÿ‘ˆ UserAdmin์ด ์œ„์น˜ํ•œ ๊ณณ
from . import models
@admin.register(models.User)  
class CustomUserAdmin(UserAdmin): # ๐Ÿ‘ˆ UserAdmin ์ƒ์†๋ฐ›์Œ
    """Custom User Admin"""
    pass

  • Django์˜ Admin์„ ์ƒ์†ํ•ด์˜ค๋ฉด, list_disply ๋ฐ list_filter๊ฐ€ ์ž๋™์œผ๋กœ ์„ธํŒ…๋˜์–ด ์žˆ์–ด ๋‚˜ํƒ€๋‚˜๊ณ , ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•œ Search bar๋„ ๊ธฐ๋ณธ ์„ธํŒ…๋˜์–ด ์žˆ์–ด์š”. ๋ฌผ๋ก  Custom๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!

2) fieldsets ์„ค์ •

  • Admin Panel ๋‚ด๋ถ€๋กœ ๋“ค์–ด๊ฐ€๋ฉด, ํ™•์žฅ์‹œํ‚จ ํ•„๋“œ(avatar, gender, bio, birthday ๋“ฑ)๋“ค์ด ๋ชจ๋‘ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋Š”๋ฐ fieldsets์„ ํ†ตํ•ด Admin Panel ๋‚ด๋ถ€๋ฅผ Custom ํ•  ์ˆ˜ ์žˆ์–ด์š”!
  • fieldsets ํฌ๋งท ํ˜•ํƒœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ธฐ์กด Django Admin์ด ๊ฐ–๊ณ  ์žˆ๋˜ field๊นŒ์ง€ ๋ชจ๋‘ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด UserAdmin.fieldsets๊ณผ ์šฐ๋ฆฌ๊ฐ€ ์ƒ์„ฑํ•œ fieldsets์„ ํ•ฉ์ณ์ค„๊ป˜์š”:)
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from . import models
# Register your models here.
@admin.register(models.User)
class CustomUserAdmin(UserAdmin):
    """Custom User Admin"""
    fieldsets = UserAdmin.fieldsets + (
        (
            "Custom Profile", # ๐Ÿ‘ˆ ๋ถ„๋ฅ˜ title
            {
                "fields": (
                    "avatar",
                    "gender",
                    "bio",
                    "birthdate",
                    "language",
                    "currency",
                    "superhost",
                )
            },
        ),
    )

3. Admin Panel Option

1) list_diplsy ์˜ต์…˜

  • list_diplsy์— ํŠœํ”Œ๋กœ ํ•„๋“œ๋ช…์„ ์ž…๋ ฅํ•˜๋ฉด Admin Panel์— ๋‚˜ํƒ€๋‚ผ ํ•„๋“œ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”.
    • ๐Ÿ”Ž list_display = ("ํ•„๋“œ๋ช…1", "ํ•„๋“œ๋ช…2", "ํ•„๋“œ๋ช…3", )
  • ๋‹จ, ManyToManyField๋Š” list_display์— ํ•„๋“œ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— Admin Panel์— ๋‚˜ํƒ€๋‚ด๊ณ ์žํ•œ๋‹ค๋ฉด ๋งค์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ list_display์— ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.
    • ์—ฌ๊ธฐ์„œ self์™€ obj๋ฅผ ์ „๋‹ฌํ•˜๋Š”๋ฐ์š”,, self๋Š” Admin Class์ธ RoomAdmin ๊ฐ€๋ฅดํ‚ค๊ณ , obj๋Š” admin์˜ ํ˜„์žฌ row๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
    • [๋งค์„œ๋“œ๋ช…].short_description๋กœ Admin Panel์— ์ถœ๋ ฅ๋  ํ•„๋“œ ์ด๋ฆ„์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”!
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
    """Room Admin Dfinition"""
    list_display = (
        "name",
        "country",
        "city",
        "price",
        "guests",
        "beds",
        "bedrooms",
        "baths",
        "check_out",
        "check_in",
        "instant_book",
        "count_amenities",
    )
    def count_amenities(self, obj):
        return obj.amenities.count() # ๐Ÿ‘ˆ ํ˜„์žฌ row์˜ amenities๋ฅผ ๊ฐฏ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜
    count_amenities.short_description = "amenities" # ๐Ÿ‘ˆ count_amenities์„ amenities๋กœ ๋ณ€๊ฒฝ 

2) list_filter ์˜ต์…˜

  • list_filter์€ ์šฐ์ธก์— ํ•„ํ„ฐ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€์‹œ์ผœ ์ค๋‹ˆ๋‹ค.
    • ๐Ÿ”Ž list_filter = ("ํ•„๋“œ๋ช…1", "ํ•„๋“œ๋ช…2", "ํ•„๋“œ๋ช…3", )
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
    """Room Admin Dfinition"""
    list_filter = (
        "instant_book",
        "host__superhost",
        "room_type",
        "amenities",
        "facilities",
        "house_rule",
        "city",
        "country",
    )  

3) search_filter ์˜ต์…˜

  • search_filter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด search bar๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”.
    • ๐Ÿ”Ž search_filter = ("ํ•„๋“œ๋ช…1", "ํ•„๋“œ๋ช…2", "ํ•„๋“œ๋ช…3", )
  • search_filter๋Š” default๋กœ icontains๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์•„์ฃผ๋ฉฐ, Prefix๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰์–ด๋ฅผ ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ์ฐพ์„์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”.
    • None(icontains) : ๋‘”๊ฐํ•œ ๊ธฐ์ค€(๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ณ„ ์•ˆํ•จ)์œผ๋กœ ์ž…๋ ฅํ•œ ๊ฒ€์ƒ‰์–ด๊ฐ€ ํฌํ•จ๋œ object๋ฅผ ๋ฐ˜ํ™˜
    • ^(startswith) : ^์˜ต์…˜์„ ๊ฐ™์ด ๋„ฃ์–ด์ฃผ๋ฉด, ์š”์ฒญํ•œ ๊ฒ€์ƒ‰์–ด๋กœ ์‹œ์ž‘๋˜๋Š” object๋ฅผ ๋ฐ˜ํ™˜
    • =(iexact) : ์š”์ฒญํ•œ ๊ฒ€์ƒ‰์–ด์™€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” object๋ฅผ ๋ฐ˜ํ™˜
  • ์ƒ์„ฑ๋œ ํ•„๋“œ ์ค‘ ForeignKey๊ฐ€ ์žˆ๋‹ค๋ฉด, ๋”๋ธ” ์–ธ๋”์Šค์ฝ”์–ด(__)๋ฅผ ํ†ตํ•ด ์ฐธ์กฐํ•˜๋Š” ๋Œ€์ƒ์˜ ๋ชจ๋ธ๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋ฌธ๋ฒ• ์Šคํƒ€์ผ์€ list_disply, list_filter ๋“ฑ์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์š”!
    • ๐Ÿ”Ž search_fields = ("^host__username", )
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
    """Room Admin Dfinition"""
    list_display = (
        "name",
        "country",
        "city",
        "price",
    )
    search_fields = (
        "city",
        "^host__username",
        "=price",
    )

4) filter_horizontal ์˜ต์…˜

  • filter_horizontal ์˜ต์…˜์€ ManyToManyField์˜ Admin Panel ๋‚ด๋ถ€์— ์ ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ์ด์—์š”.
  • filter_horizontal ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด, ํ•„๋“œ์˜ ์Šคํƒ€์ผ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ณ€๊ฒฝํ•ด์ค˜์š”.
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
    """Room Admin Dfinition"""
    filter_horizontal = (
        "amenities",
        "facilities",
        "house_rule",
    )

๐Ÿ‘‰ default

๐Ÿ‘‰ filter_horizontal

5) ordering ์˜ต์…˜

  • ordering ์˜ต์…˜์— ํ•„๋“œ๊ฐ’์„ ์ง€์ •ํ•˜๋ฉด, Admin Panel์— ์ •๋ ฌ ๋ฒ„ํŠผ(์‚ผ๊ฐํ˜• ๋ฒ„ํŠผ)์„ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
    """Room Admin Dfinition"""
    ordering = (
        "name",
        "price",
    )    

6) raw_id_fields ์˜ต์…˜

  • Admin Panel ๋‚ด๋ถ€๋กœ ๋“ค์–ด๊ฐ€๋ณผ ๊นŒ์š”? ์‚ฌ์šฉ์ž๊ฐ€ ๋Š˜์–ด๋‚œ๋‹ค๋ฉด, ํ•„๋“œ๊ฐ’์ด ๋งŽ์•„์ ธ ์Šคํฌ๋กค์˜ ์••๋ฐ•์œผ๋กœ ๋ถˆํŽธ์„ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค:)
  • ์ด๋Ÿด ๊ฒฝ์šฐ, raw_id_fields๋กœ ํ•ด๋‹น ํ•„๋“œ๋ฅผ ์ง€์ •ํ•ด์ฃผ๋ฉด ํŒ์—…์ฐฝ์„ ๋งŒ๋“ค์–ด์ค˜์š”. ์›ํ•˜๋Š” ๊ฐ’์„ ์ฐพ๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค!
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
    """Room Admin Dfinition"""
    raw_id_fields = ("host",)    


4. Model์˜ ๋งค์„œ๋“œ๋ฅผ admin์—์„œ ํ™œ์šฉํ•˜๊ธฐ

  • Admin Panel์—๋Š” Model์—์„œ ์„ ์–ธํ•œ ํ•„๋“œ๊ฐ’๋งŒ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์—์š”. ํ•„์š”์— ์˜ํ•ด์„œ admin.py ๋˜๋Š” models.py์— ๋งค์„œ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ ์ž์œ ๋กญ๊ฒŒ list_display์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค. ๊ฐ Review์— ๋Œ€ํ•œ "ํ‰์  ์ •๋ณด"๋ฅผ Model์—์„œ ๋งค์„œ๋“œ ๋งŒ๋“ค๊ณ  list_display์— ์ถ”๊ฐ€ํ•ด ๋ณผ๊ป˜์š”:)
  • "ํ‰์  ์ •๋ณด"๋ฅผ Admin Panel๋งŒ์ด ์•„๋‹Œ ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ Templates ์˜์—ญ์—์„œ๋„ ์‚ฌ์šฉํ•  ์˜ˆ์ •์ด๋ผ๋ฉด Model ์˜์—ญ(models.py)์—์„œ ๋งค์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์•„์š”. Model์—์„œ ์ƒ์„ฑ๋œ ๋งค์„œ๋“œ๋Š” Admin Panel ๋ฟ๋งŒ์•„๋‹ˆ๋ผ Templates ์˜์—ญ์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ !
  • ๋งŒ์•ฝ Admin Panel์—์„œ๋งŒ ํ•ด๋‹น ๋งค์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๊ณ„ํš์ด๋ผ๋ฉด admin.py์— ๋งค์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

1) reviews/models.py

  • ๊ฐ Review Object์˜ ํ‰์ ์˜ ํ‰๊ท ์„ ๊ตฌํ•ด์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋งค์„œ๋“œ ์ž‘์„ฑํ–ˆ์–ด์š”.
    • ๊ฐ ๊ฐ์‹ค์˜ ์ ์ˆ˜ : accuracy, communication, cleanliness, location, check_in, value
  • ํ•ด๋‹น ๋งค์„œ๋“œ๋ช…์„ list_display์— ์ถ”๊ฐ€๋งŒํ•˜๋ฉด Admin Panel์—์„œ ๊ฐ Reivew์— ๋Œ€ํ•œ ํ‰์ • ์ •๋ณด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.
  • short_description์€ admin.py ๋ฐ models.py ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
    • ๐Ÿ”Ž rating_average.short_description = "Avg."
from django.db import models
from core import models as core_models
# Create your models here.
class Review(core_models.TimeStampedModel):
    """Review Model Definition"""
    review = models.TextField()
    accuracy = models.IntegerField()
    communication = models.IntegerField()
    cleanliness = models.IntegerField()
    location = models.IntegerField()
    check_in = models.IntegerField()
    value = models.IntegerField()
    user = models.ForeignKey(
        "users.User", related_name="reviews", on_delete=models.CASCADE
    )
    room = models.ForeignKey(
        "rooms.Room", related_name="reviews", on_delete=models.CASCADE
    )
    def __str__(self):
        return f"{self.review} - {self.room}"
    def rating_average(self):
        avg = (
            self.accuracy
            + self.communication
            + self.cleanliness
            + self.location
            + self.check_in
            + self.value
        ) / 6
        return round(avg, 2) # ๐Ÿ‘ˆ ์†Œ์ˆ˜์  2์งธ์ž๋ฆฌ๊นŒ์ง€ ๋‚˜ํƒ€๋‚ผ๊ฑฐ์—์š”:)
    rating_average.short_description = "Avg."

2) reviews.admin.py

  • __str__ ๋งค์ง๋งค์„œ๊ฐ€ list_display์— ๋ฎ์–ด์”Œ์–ด์ ธ Admin Panel์— ๋ณด์ด์ง€ ์•Š์„ ๋•Œ๋Š” ๋‹นํ™ฉํ•˜์ง€ ๋ง๊ณ ,, "list_display"์— __str__ ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋˜์š”!
from django.contrib import admin
from . import models
# Register your models here.
@admin.register(models.Review)
class ReviewAdmin(admin.ModelAdmin):
    """Review Admin Definition"""
    list_display = (
        "__str__",
        "rating_average",
    )

  • ๊ฐ ๊ฐ์‹ค์ด ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์— ์˜ํ•ด ์ด๋ฏธ ์ด์šฉํ–ˆ์—ˆ์„ ์ˆ˜ ์žˆ๊ณ , ๊ทธ๋ ‡๋‹ค๋ฉด ํ‰์ ๋„ ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ์กด์žฌํ• ๊บผ์—์š”. ์ด๋ฒˆ์—๋Š” ๊ฐ ๊ฐ์‹ค์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ ํ‰์  ์ •๋ณด์˜ ํ‰๊ท ์„ Admin Panel๊ณผ Front ์˜์—ญ์—์„œ ๋‚˜ํƒ€๋‚ด๊ณ ์ž ํ•ด์š”.
  • Review ๋ชจ๋ธ์€ ForeignKey๋กœ Room์„ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Room์—์„œ๋Š” related_name์˜ ๊ฐ’์„ ํ†ตํ•ด์„œ ๊ฐ ๊ฐ์‹ค์„ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ชจ๋“  Review๋“ค์˜ ์ •๋ณด์— ์—ญ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์š”:)

3) rooms/models.py

  • ๊ฐ ๊ฐ์‹ค์„ ์ฐธ์กฐํ•˜๋Š” ๋ชจ๋“  Review ์ •๋ณด๋ฅผ all_reviews์— ๋‹ด์•˜์–ด์š”. "self.reviews.all()"์—์„œ reviews๋Š” ์–ด๋””์„œ ์™“์„๊นŒ์š”? roomํ•„๋“œ(reviews/models.py)์— related_name ๊ฐ’์ž…๋‹ˆ๋‹ค.
    • ๐Ÿ”Ž all_reviews = self.reviews.all()
  • ์ด์ œ all_reviews์— ๊ฐ ๊ฐ์‹ค์„ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ชจ๋“  Review๋ฅผ ๋‹ด์•„๋‘์—ˆ์–ด์š”. rating_average() ๋งค์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ‰์  ๊ฐ’์„ ๋ชจ๋‘ ํ•ฉํ•œ ๋’ค, all_reviews์˜ ๊ธธ์ด๋งŒํผ ๋‚˜๋ˆ  ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ฐ ๊ฐ์‹ค์— ๋Œ€ํ•œ ํ‰์  ์ •๋ณด ์ œ๊ณตํ•ด์ค˜์š”.
    • ๐Ÿ”Ž all_rating += review.rating_average()
class Room(core_models.TimeStampedModel):
    """Room Model Definifion"""
    def total_rating(self):
        all_reviews = self.reviews.all()
        all_rating = 0
        if len(all_reviews) != 0:
            for review in all_reviews:
                all_rating += review.rating_average() # ๐Ÿ‘ˆ ๋งค์„œ๋“œ๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ
            return all_rating / len(all_reviews)
        else: # ๐Ÿ‘ˆ Review๊ฐ€ 1๊ฐœ๋„ ์ž‘์„ฑ๋˜์ง€ ์•Š์€ ๊ฐ์‹ค์ด ์กด์žฌํ•  ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•œ ๋ฐฉ์–ด์ฝ”๋“œ์—์š”:)
            return 0
    total_rating.short_description = "rating"


5. Timezone Utils ์‚ฌ์šฉํ•˜๊ธฐ

1) Timezone Utils

  • Python์˜ Time ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , TimeZone์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” settgins.py์—์„œ ์„ค์ •๋œ TimeZone์ด Django์˜ ์„œ๋ฒ„์˜ ์‹œ๊ฐ„์„ ๊ด€์žฅํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.
    • ๐Ÿ”Ž from django.utils import timezone
  • ๋ฐ˜ํ™˜๊ฐ’์„ Boolean ์•„์ด์ฝ˜์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•
    • ๐Ÿ”Ž in_progress.boolean = True
from django.db import models
from django.utils import timezone # ๐Ÿ‘ˆ timezone util์„ ๊ฐ€์ ธ์˜ค๊ธฐ
from core import models as core_models
# Create your models here.
class Reservation(core_models.TimeStampedModel):
    """Reservation Model Definition"""
    STATUS_PENDING = "pending"
    STATUS_CONFIRMED = "confirmed"
    STATUS_CANCELED = "canceled"
    STATUS_CHOICES = (
        (STATUS_PENDING, "Pending"),
        (STATUS_CONFIRMED, "Confirmed"),
        (STATUS_CANCELED, "Canceled"),
    )
    status = models.CharField(
        max_length=12, choices=STATUS_CHOICES, default=STATUS_PENDING
    )
    check_in = models.DateField()
    check_out = models.DateField()
    guest = models.ForeignKey(
        "users.User", related_name="reservations", on_delete=models.CASCADE
    )
    room = models.ForeignKey(
        "rooms.Room", related_name="reservations", on_delete=models.CASCADE
    )
    def __str__(self):
        return f"{self.room} - {self.check_in}"
    def in_progress(self):
        now = timezone.now().date() # ๐Ÿ‘ˆ ํ˜„์žฌ ์„œ๋ฒ„ ๋‚ ์งœ
        return now >= self.check_in and now <= self.check_out
    in_progress.boolean = True  # ๐Ÿ‘ˆ return๊ฐ’์„ True, False๊ฐ€ ์•„๋‹Œ ์•„์ด์ฝ˜์œผ๋กœ ๋‚˜ํƒ€๋‚ด์ค˜์š”.
    def is_finished(self):
        now = timezone.now().date() # ๐Ÿ‘ˆ ํ˜„์žฌ ์„œ๋ฒ„ ๋‚ ์งœ
        return now > self.check_out
    is_finished.boolean = True # ๐Ÿ‘ˆ return๊ฐ’์„ True, False๊ฐ€ ์•„๋‹Œ ์•„์ด์ฝ˜์œผ๋กœ ๋‚˜ํƒ€๋‚ด์ค˜์š”.


6. Save Method ์˜ค๋ฒ„๋ผ์ด๋”ฉ

  • Save Method๋ฅผ ๊ฐ€๋กœ์ฑ„์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜๋Š”๋ฐ์š”,, ๊ทธ ์ด์œ ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณผ๊ป˜์š”.
  • "users/models.py"์˜ city ํ•„๋“œ๋Š” host๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์ด ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ์žฅ์†Œ์ž„์— ๋ถˆ๊ตฌํ•˜๊ณ  ๋Œ€์†Œ๋ฌธ์ž ๋“ฑ์˜ ์ฐจ์ด๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”. ์–ด๋–ค host๋Š” Seoul๋กœ ์ž…๋ ฅํ•˜๊ณ , ๋˜ ๋‹ค๋ฅธ host๋Š” seoul๋กœ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๊ฒŸ์ฃ .
  • country์ฒ˜๋Ÿผ ์ •ํ•ด์ง„ ์„ ํƒ ๋ชฉ๋ก์„ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ์œผ๋‚˜, city๋Š” ์–‘์ด ๋ฐฉ๋Œ€ํ•˜๊ณ  ๋ชจ๋“  city๋ฅผ ์ œ๊ณตํ•˜๋ฉด ์‹ค์ œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ถˆํ•„์š”ํ•œ ๊ฐ’์ด ์กด์žฌํ• ๊ฑฐ์—์š”.
  • ์ด์— Model ๊ฐ’์˜ ๋“ฑ๋ก์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋งก๊ธฐ์ง€๋งŒ, ๋™์ผํ•œ ๊ฐ’์ธ ๊ฒฝ์šฐ ์ตœ๋Œ€ํ•œ ๊ฐ’๋“ค์„ ํ†ต์ผํ•˜์—ฌ ์ €์žฅ๋  ์ˆ˜ ์žˆ๊ฒŒํ•  ํ•„์š”๊ฐ€ ์žˆ์–ด์š”. ์ด๋Ÿด ๋•Œ, save() ๋งค์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์„œ ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ์ „์— Save Envent๋ฅผ ๊ฐ€๋กœ์ฑ„์„œ ํ•ด๋‹น ๊ฐ’์„ ์ˆ˜์ •ํ•œ ๋’ค, ์ €์žฅ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด์š”!

1) rooms.models.py

  • form์— ์ž…๋ ฅํ•œ ์ •๋ณด๊ฐ€ DB์— ํ•ด๋‹น ํ•„๋“œ๋กœ ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด save() ๋งค์„œ๋“œ์˜ ์—ญํ• ์ด์—์š”. ์ฆ‰, Save Event๋ฅผ ๊ฐ€๋กœ์ฑˆ๋‹ค๋Š” ๊ฒƒ์€ ๊ธฐ์กด์— save() ๋งค์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ๊ฐ’์„ ๋‹ค๋ฃฌ ๋’ค, super()๋ฅผ ํ†ตํ•ด save()์˜ ๋ณธ๋ž˜ ๊ธฐ๋Šฅ์„ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ์ €์žฅ๋˜๊ธฐ ์ „์— ์ž ์‹œ ๊ฐ’์„ ๊ฐ€๋กœ์ฑ„์„œ ์กฐ์น˜๋ฅผ ์ทจํ•˜๊ณ  ์ €์žฅ์‹œํ‚ค๋Š” ๊ฑฐ์ฃ !
from django.db import models
from django_countries.fields import CountryField
from core import models as core_models
# Create your models here.
class Room(core_models.TimeStampedModel):
    """Room Model Definifion"""
    ...
    ...
    city = models.CharField(max_length=80)
    ...
    ...
    def save(self, *args, **kwargs):
        self.city = str.capitalize(self.city) # ๐Ÿ‘ˆ ์•ž๊ธ€์ž๋ฅผ ๋Œ€๋ถ„์ž๋กœ ๋ฐ”๊พธ๊ณ  
        super().save(*args, **kwargs) # ๐Ÿ‘ˆ ์›๋ž˜ save ๋งค์„œ๋“œ๋ฅผ ์‹คํ–‰
profile
Keep Going, Keep Coding!

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