1. Django Tutorial(Airbnb) - Django Session & save_m2m

ID์งฑ์žฌยท2021๋…„ 8์›” 26์ผ
0

Django

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

๐ŸŒˆ Django Session

๐Ÿ”ฅ Swich Btn for Session

๐Ÿ”ฅ Create Room in Host Mode


๐Ÿ“Œ ์ด ํฌ์ŠคํŒ…์—์„œ๋Š” Django์˜ Session์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“œ(Guest/Host) ์ „ํ™˜์„ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ์ •๋ณด๋ฅผ DB์— ์ €์žฅํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. Guest Mode๋‚˜ Host Mode์˜ ๊ฒฝ์šฐ Session์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๋” ๊ฐ„ํŽธํ•ฉ๋‹ˆ๋‹ค. Session์€ Django์˜ Back๋‹จ์—์„œ ์ •๋ณด๋ฅผ ์ž ์‹œ ์œ ์ง€ํ•˜๋‹ค๊ฐ€ Logoutํ•  ๊ฒฝ์šฐ ๋ชจ๋‘ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ํ™”ํ์ •๋ณด(currency)์ฒ˜๋Ÿผ ์ผ์‹œ์ ์œผ๋กœ ํ•„์š”ํ•œ ์ •๋ณด๋“ค์€ ์‚ฌ์‹ค Model์— field๋ฅผ ๋งŒ๋“ค์–ด ์ €์žฅํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค Session์„ ์ด์šฉํ•˜๋Š”๊ฒŒ ๋” ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.!


1. Swich Btn for Session

"users/views.py"์—์„œ session์„ ํ™œ์šฉํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ์„  session์€ login๋œ ์ƒํƒœ์—ฌ์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— session์— ์˜ฌ๋ฆฌ๊ฑฐ๋‚˜ ๋‚ด๋ฆด ๋•Œ ๋ชจ๋‘ login์ด ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ "login_required" ๋ฐ์ฝ”๋ ˆ์ด์…˜์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ๐Ÿ”Ž from django.contrib.auth.decorators import login_required

Host ๋ชจ๋“œ๊ฐ€ ์š”์ฒญ๋˜๋ฉด "start_hosting" ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ , ๋‹ค์‹œ Guest ๋ชจ๋“œ๋ฅผ ์š”์ฒญํ•˜๋ฉด "stop_hosting" ํ•จ์ˆ˜๋ฅผ ์ž‘๋™์‹œํ‚ต๋‹ˆ๋‹ค.

# users/views.py
from django.contrib.auth.decorators import login_required # ๐Ÿ‘ˆ "login_required" import
...
...
@login_required
def start_hosting(request): 
    request.session["is_hosting"] = True  # ๐Ÿ‘ˆ session์— "is_hosting" ์ถ”๊ฐ€
    return redirect(reverse("core:home"))
@login_required
def stop_hosting(request):
    try:
        del request.session["is_hosting"]  # ๐Ÿ‘ˆ session์—์„œ "is_hosting" ์ œ๊ฑฐ
    except KeyError:
        pass    
    return redirect(reverse("core:home"))

์œ„์— session ์ „ํ™˜ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋กœ ๊ธฐ๋Šฅํ•˜๊ฒŒ ํ†ตํ•ฉ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์ฒ˜๋Ÿผ ๋‘ ๊ฐœ์˜ ๊ฒฝ์šฐ๋ฐ–์— ์—†์„ ๋•Œ์—๋Š” try ๊ตฌ๋ฌธ์œผ๋กœ ์ „ํ™˜์‹œ์ผœ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, session์—์„œ "is_hosting"๋ฅผ ์ œ๊ฑฐํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๊ณ , KeyError๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด session์— "is_hosting"์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด์ฃ . ์ด ๋ฐฉ๋ฒ•์€ ์‚ฌ์šฉํ•˜๋ฉด, url ๊ฒฝ๋กœ๋ฅผ 1๊ฐœ๋งŒ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค!

from django.contrib.auth.decorators import login_required # ๐Ÿ‘ˆ "login_required" import
...
...
@login_required
def switch_hosting(request):
    try:
        del request.session["is_hosting"] # ๐Ÿ‘ˆ ์šฐ์„  ์ œ๊ฑฐ๋ฅผ ์‹œ๋„ํ•˜๊ณ , 
    except KeyError:
        request.session["is_hosting"] = True # ๐Ÿ‘ˆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ถ”๊ฐ€
    return redirect(reverse("core:home"))
  • Url๊ณผ View๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ๋งคํ•‘ํ•ด์ฃผ๋ฉด๋ฉ๋‹ˆ๋‹ค. ๋งˆ์น˜ View์˜ ํ•จ์ˆ˜๋ฅผ toggle ๊ธฐ๋Šฅ์ฒ˜๋Ÿผ ์ž‘๋™์‹œํ‚ค๋Š” ๊ฒƒ์ด์ฃ !
from django.urls import path
from . import views
app_name = "users"
urlpatterns = [
    ...
    ...
    ...    
    path("switch-hosting/", views.switch_hosting, name="switch-hosting"), # ๐Ÿ‘ˆ swaich-hosting
]

์ด์ œ View์™€ Url์„ ๋งคํ•‘ํ•˜์˜€์œผ๋‹ˆ, Template์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ํด๋ฆญํ•œ ๋ฒ„ํŠผ์„ "partials/nav.html"์— ์ƒ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฒ„ํŠผ์€ swich๋˜๊ธฐ ๋•Œ๋ฌธ์— session์ด ์ถ”๊ฐ€๋œ ์ƒํƒœ์ผ ๋•Œ๋Š” Host ๋ชจ๋“œ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— "Stop hosting" ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜์•ผํ•˜๊ณ , ์ถ”๊ฐ€๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ๋Š” "Start hosting" ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด์™€ ํ•จ๊ป˜ Host ๋ชจ๋“œ์ผ ๋•Œ๋Š” ๊ฐ์‹ค์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” "Create Room" ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

<ul class="flex items-center text-sm font-medium h-full">
    {% if user.is_authenticated %}
        <li class="nav_link"> # ๐Ÿ‘ˆ session ์ „ํ™˜ Btn
            <a href="{% url 'users:switch-hosting' %}">
                {% if request.session.is_hosting %} # ๐Ÿ‘ˆ session์— "is_hosting"์ด ์กด์žฌํ•œ๋‹ค๋ฉด,,
                    Stop hosting
                {% else %} # ๐Ÿ‘ˆ session์— "is_hosting"์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด,,
                    Start hosting
                {% endif %}
            </a>
        </li>
        {% if request.session.is_hosting %} # ๐Ÿ‘ˆ host mode์ผ ๋•Œ, "Create Room" bnt ๋…ธ์ถœ 
            <li class="nav_link"><a href="#">Create Room</a></li>
        {% endif %}
        <li class="nav_link"><a href="{{user.get_absolute_url}}">Profile</a></li>
        <li class="nav_link"><a href="{% url "users:logout" %}">Log out</a></li>
    {% else %}
        <li class="nav_link"><a href="{% url "users:login" %}">Log in</a></li>
        <li class="nav_link"><a href="{% url "users:signup" %}">Sign up</a></li>
    {% endif %}    
</ul>



2. Create Room in Host Mode

1) Create Room

Host ๋ชจ๋“œ์ผ ๋•Œ๋งŒ ๊ฐ์‹ค์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„ํŠผ์„ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์œผ๋‹ˆ ์ด๋ฅผ ๊ธฐ๋Šฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ฒ˜๋ฆฌํ•ด๋ณผ๊ป˜์š”. CBV๋กœ ๋งŒ๋“ค ๋•Œ, save() ๋งค์„œ๋“œ๋ฅผ ๊ฐ€๋กœ์ฑ„์•ผํ•  ๋•Œ๋Š” CreateView ๋ณด๋‹ค FormView ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

class CreateRoomView(user_mixins.LoggedInOnlyView, FormView):
    form_class = forms.CreateRoomForm # ๐Ÿ‘ˆ ํ…œํ”Œ๋ฆฟ์— ์ž…๋ ฅ์„ ๋ฐ›๊ธฐ ์œ„ํ•œ form์ž…๋‹ˆ๋‹ค.
    template_name = "rooms/room_create.html" # ๐Ÿ‘ˆ ๊ฐ์‹ค์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด renderํ•  ํ…œํ”Œ๋ฆฟ์ž…๋‹ˆ๋‹ค.

"room/forms.py"์˜ "CreateRoomForm"์€ ModelForm์„ ์ƒ์†๋ฐ›์•„, ๊ฐ์‹ค ์ƒ์„ฑ์„ ์œ„ํ•œ field๋ฅผ ์ง€์ •ํ•ด์ค๋‹ˆ๋‹ค.

class CreateRoomForm(forms.ModelForm):
    class Meta:
        model = models.Room
        fields = (
            "name",
            "description",
            "country",
            "city",
            "price",
            "address",
            "guests",
            "beds",
            "bedrooms",
            "baths",
            "check_in",
            "check_out",
            "instant_book",
            "room_type",
            "amenities",
            "facilities",
            "house_rule",
        )

"CreateRoomView"๋ฅผ ์ž‘๋™์‹œํ‚ฌ Url ๊ฒฝ๋กœ๋ฅผ ๋งคํ•‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

from django.urls import path
from . import views
app_name = "rooms"
urlpatterns = [
    path("create/", views.CreateRoomView.as_view(), name="create"), # ๐Ÿ‘ˆ CreateRoomView๋ฅผ ์—ฐ๊ฒฐํ•ด์ค๋‹ˆ๋‹ค.
    path("<int:pk>/", views.RoomDetail.as_view(), name="detail"),
    path("<int:pk>/edit/", views.EditRoomView.as_view(), name="edit"),
    path("<int:pk>/photos/", views.RoomPhotosView.as_view(), name="photos"),
    path("<int:pk>/photos/add", views.AddPhotoView.as_view(), name="add-photos"),
    path(
        "<int:room_pk>/photos/<int:photo_pk>/delete/",
        views.delete_photo,
        name="delete-photo",
    ),
    path(
        "<int:room_pk>/photos/<int:photo_pk>/edit/",
        views.EditPhotoView.as_view(),
        name="edit-photo",
    ),
    path("search/", views.SearchView.as_view(), name="search"),
]
  • "Create Room" ๋ฒ„ํŠผ์— ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ด์ค๋‹ˆ๋‹ค.
<ul class="flex items-center text-sm font-medium h-full">
    {% if user.is_authenticated %}
        <li class="nav_link">
            <a href="{% url 'users:switch-hosting' %}">
                {% if request.session.is_hosting %}
                    Stop hosting
                {% else %}
                    Start hosting
                {% endif %}
            </a>
        </li>
        {% if request.session.is_hosting %} # ๐Ÿ‘‡ url์„ ์—ฐ๊ฒฐํ•ด์ค„๊ป˜์š”:)
            <li class="nav_link"><a href="{% url 'rooms:create' %}">Create Room</a></li>
        {% endif %}        
        <li class="nav_link"><a href="{{user.get_absolute_url}}">Profile</a></li>
        <li class="nav_link"><a href="{% url "users:logout" %}">Log out</a></li>
    {% else %}
        <li class="nav_link"><a href="{% url "users:login" %}">Log in</a></li>
        <li class="nav_link"><a href="{% url "users:signup" %}">Sign up</a></li>
    {% endif %}    
</ul>

2) save_m2m()

์ด์ œ form์—์„œ Room Object๋ฅผ ์ƒ์„ฑ ํ›„,, ์ €์žฅํ•˜๊ธฐ ์ „ ๊ฐ€๋กœ์ฑ„์„œ ์ƒ์„ฑ๋œ Object๋ฅผ View๋‹จ์œผ๋กœ ์ „๋‹ฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

class CreateRoomForm(forms.ModelForm):
    class Meta:
        model = models.Room
        fields = (
            "name",
            "description",
            "country",
            "city",
            "price",
            "address",
            "guests",
            "beds",
            "bedrooms",
            "baths",
            "check_in",
            "check_out",
            "instant_book",
            "room_type",
            "amenities",
            "facilities",
            "house_rule",
        )
    def save(self, *args, **kwargs):
        room = super().save(commit=False) # ๐Ÿ‘ˆ Object๋ฅผ ์ƒ์„ฑ๊นŒ์ง€๋งŒ ํ•ฉ๋‹ˆ๋‹ค.
        return room # ๐Ÿ‘ˆ ๊ทธ Object๋ฅผ View๋กœ returnํ•ฉ๋‹ˆ๋‹ค.

FBV์—์„œ๋Š” is_valid()๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, CBV์—์„œ๋Š” form_vaild๋ฅผ ์‚ฌ์šฉํ•ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰์‹œํ‚ต๋‹ˆ๋‹ค. ์œ ํšจํ•˜๋‹ค๋ฉด, save ๋งค์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ "CreateRoomForm"์—์„œ Object์ƒ์„ฑ ํ›„ ์ €์žฅํ•˜๊ธฐ ์ „ ์ƒํƒœ๋ฅผ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค. ์ดํ›„ ํ˜„์žฌ ์‚ฌ์šฉ์ž๋ฅผ host๋กœ ์ง€์ •ํ•œ ๋’ค, ์ €์žฅ์‹œํ‚ต๋‹ˆ๋‹ค.
๋งˆ์ง€๋ง‰์œผ๋กœ ์ €์žฅํ•  field๋“ค ์ค‘ Many-to-Mnay field๊ฐ€ ์žˆ๋‹ค๋ฉด,, save_m2m ๋งค์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ €์žฅ์‹œํ‚ต๋‹ˆ๋‹ค.

class CreateRoomView(user_mixins.LoggedInOnlyView, FormView):
    form_class = forms.CreateRoomForm
    template_name = "rooms/room_create.html"
    def form_valid(self, form):
        room = form.save() # ๐Ÿ‘ˆ Form์—์„œ ์ƒ์„ฑ๋œ Object ๊ฐ€์ ธ์™€์š”:)
        room.host = self.request.user  # ๐Ÿ‘ˆ ํ˜„์žฌ ์‚ฌ์šฉ์ž๋ฅผ host๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
        room.save()  # ๐Ÿ‘ˆ ์ €์žฅ.
        form.save_m2m() # ๐Ÿ‘ˆ Many-to-Many ํ•„๋“œ๋ฅผ ์ €์žฅํ•ด์ค˜์š”:)
        messages.success(self.request, "Room Uploaded")
        return redirect(reverse("rooms:detail", kwargs={"pk": room.pk})) # ๐Ÿ‘ˆ ์ƒ์„ฑํ•œ ๋ฐฉ์œผ๋กœ rediect

profile
Keep Going, Keep Coding!

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