SearchView

Jeong Ha Seung·2021년 11월 25일

rooms/views.py

from django.shortcuts import render
from django_countries import countries
...

def search(request):
    city = request.GET.get("city", "Anywhere")
    city = str.capitalize(city)
    country = request.GET.get("country", "KR") #Default 값으로 KR
    room_type = int(request.GET.get("room_type", 0)) #Default 값으로 0, url 값을 get으로 가져오면 str형태이기 때문에 int로 수정
    price = int(request.GET.get("price", 0))
    guests = int(request.GET.get("guests", 0))
    bedrooms = int(request.GET.get("bedrooms", 0))
    beds = int(request.GET.get("beds", 0))
    baths = int(request.GET.get("baths", 0))
    instant = bool(request.GET.get("instant", False))
    super_host = bool(request.GET.get("superhost", False))
    s_amenities = request.GET.getlist("amenities") 
    s_facilities = request.GET.getlist("facilities")
	#단, check 박스는 선택 결과가 1개일 수도 있고 더 많을 수도 있기 때문에 사용자가 선택한 값들을 getlist로 받아올 수 있다. getlist는 그 값들을 배열 형태로 가져온다.

    form = {
        "city": city,
        "s_room_type": room_type,
        "s_country": country,
        "price": price,
        "guests": guests,
    "bedrooms": bedrooms,
    "beds": beds,
    "baths": baths,
    "s_amenities": s_amenities,
    "s_facilities": s_facilities,
    "instant": instant,
    "superhost": superhost,
    }

room_types = models.RoomType.objects.all()
amenities = models.Amenity.objects.all()
facilities = models.Facility.objects.al
choices = {
    "countries": countries,
    "room_types": room_types,
    "amenities": amenities,
    "facilities": facilities,
}
filter_args = {} #filter()에 들어갈 parameter를 filter_args에 담아서 unpack

if city != "Anywhere":
    filter_args["city__startswith"] = city

filter_args["country"] = country

if room_type != 0:
    filter_args["room_type__pk"] = room_type #Foreign Key 이용

if price != 0:
    filter_args["price__lte"] = price #~이하

if guests != 0:
    filter_args["guests__gte"] = guests #이상

if bedrooms != 0:
    filter_args["bedrooms__gte"] = bedrooms

if beds != 0:
    filter_args["beds__gte"] = beds

if baths != 0:
    filter_args["baths__gte"] = baths

if instant is True:
    filter_args["instant_book"] = True

if superhost is True:
    filter_args["host__superhost"] = True

if len(s_amenities) > 0:
    for s_amenity in s_amenities:
        filter_args["amenities__pk"] = int(s_amenity)

if len(s_facilities) > 0:
    for s_facility in s_facilities:
        filter_args["facilities__pk"] = int(s_facility)

rooms = models.Room.objects.filter(**filter_args) #filter를 이용해서 dictionary로 만들어 한번에 전달하면 편리하다.

return render(request, "rooms/search.html", {**form, **choices, "rooms": rooms})

rooms/urls.py

urlpatterns = [
    path("<int:pk>", views.RoomDetail.as_view(), name="detail"),
    path("search/", views.search, name="search"), #다음과 같이 추가, search 다음에 꼭 /를 붙여준다. 안 그럼 에러남
]

templates/rooms/search.html

{% extends "base.html" %}

{% block page_title %}
    Search
{% endblock page_title %}

{% block search-bar %}
{% endblock search-bar %}

{% block content %}

<h2>Search!</h2>

<form method="get" action="{% url "rooms:search" %}">
    <div>
        <label for="city">City</label>
        <input value="{{city}}" id="city" name="city" placeholder="Search By City" />
    </div>

    <div>
        <label for="country">Country</label>
        <select id="country" name="country" >
            {% for country in countries  %}
                <option value="{{country.code}}" {% if country.code == s_country  %}selected{% endif %}>{{country.name}}</option>
            {% endfor %}
        </select>
    </div>

    <div>
        <label for="room_type">Room Type</label>
        <select id="room_type" name="room_type">
            <option value="0" {% if s_room_type == 0  %}selected{% endif %}>Any kind</option>
            {% for room_type in room_types  %}
                <option value="{{room_type.pk}}" {% if s_room_type == room_type.pk  %}selected{% endif %}>{{room_type.name}}</option>
            {% endfor %}
        </select>
    </div>
    <div>
        <label for="price">Price</label>
        <input value="{{price}}" type="number" name="price" id="price" placeholder="Price" />
    </div>
    <div>
        <label for="guests">Guests</label>
        <input value="{{guests}}" type="number" name="guests" id="guests" placeholder="Guests" />
    </div>
    <div>
        <label for="bedrooms">Bedrooms</label>
        <input value="{{bedrooms}}" type="number" name="bedrooms" id="bedrooms" placeholder="Bedrooms" />
    </div>
    <div>
        <label for="beds">Beds</label>
        <input value="{{beds}}" type="number" name="beds" id="beds" placeholder="Beds" />
    </div>
    <div>
        <label for="baths">Baths</label>
        <input value="{{baths}}" type="number" name="baths" id="baths" placeholder="Baths" />
    </div>
    <div>
        <label for="instant">Instant Book Only?</label>
        <input type="checkbox" name="instant" id="instant" {% if instant  %}checked{% endif %} />
    </div>
    <div>
        <label for="superhost">By Superhost Only?</label>
        <input type="checkbox" name="superhost" id="superhost" {% if superhost %}checked{% endif %} />
    </div>
    <div>
        <h3>Amenities</h3>
        <ul>
            {% for amenity in amenities %}
                <li>
                    <label for="a_{{amenity.pk}}">{{amenity.name}}</label>
                    <input 
                        id="a_{{amenity.pk}}"
                        name="amenities"
                        type="checkbox"
                        value={{amenity.pk}}
                        {% if amenity.pk|slugify in s_amenities %}
                            checked
                        {% endif %}
                    />
                </li>
            {% endfor %}
        </ul>
    </div>
    <div>
        <h3>Facilities</h3>
        <ul>
            {% for facility in facilities %}
                <li>
                    <label for="f_{{facility.pk}}">{{facility.name}}</label>
                    <input 
                        id="f_{{facility.pk}}"
                        name="facilities"
                        type="checkbox"
                        value={{facility.pk}}
                        {% if facility.pk|slugify in s_facilities %}
                            checked
                        {% endif %}
                    />
                </li>
            {% endfor %}
        </ul>
    </div>
    <button>Search</button>
</form>

<h3>Results</h3>

#template에 rooms로 전달했기 때문에 for문 이용하여 방 출력
{% for room in rooms %}
    <h3>{{room.name}}</h3>
{% endfor %}

{% endblock content %}

templates/partials/nav.html

<a href="{% url "core:home" %}">Nbnb</a>
<ul>
    <li><a href="#">Login</a></li>
</ul> 

templates/base.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>{% block page_title %}{% endblock page_title %}| Nbnb</title>
  </head>
  <body>
    <header>
      {% include "partials/nav.html" %}
      {% block search-bar %}
        <form method="get" action="{% url "rooms:search" %}">
            <input name="city" placeholder="Search By City" />
        </form>
      {% endblock search-bar %}
    </header>

    {% block content %}{% endblock %}

    {% include "partials/footer.html" %}
  </body>
</html>

Django Form으로 Search Bar 구현

forms.py에 class를 만들어서 Django Form을 받아 상속받아 사용하면 간편하게 form을 만들 수 있다.
Django가 제공하는 forms를 가져온뒤 Form을 상속받아 이용하면 된다. forms.Form 👉 이렇게


amenities,facilities
의 경우에는 ModelMultipleChoiceField를 사용해서 widget을 통해 form 형태를 바꿔준다.
또한 checkbox 형태로 다중 선택할 수 있도록 ChecboxSelectMultiple 적용

rooms/forms.py

from django import forms
from django_countries.fields import CountryField
from . import models


class SearchForm(forms.Form):

    city = forms.CharField(initial="Anywhere")
    country = CountryField(default="KR").formfield()
    room_type = forms.ModelChoiceField(required=False, empty_label="Any kind", queryset=models.RoomType.objects.all())
    price = forms.IntegerField(required=False)
    guests = forms.IntegerField(required=False)
    bedrooms = forms.IntegerField(required=False)
    beds = forms.IntegerField(required=False)
    baths = forms.IntegerField(required=False)
    instant_book = forms.BooleanField(required=False)
    superhost = forms.BooleanField(required=False)
    amenities = forms.ModelMultipleChoiceField(
      required=False,
      queryset=models.Amenity.objects.all(),
      widget=forms.CheckboxSelectMultiple,
    )
    facilities = forms.ModelMultipleChoiceField(
      required=False,
      queryset=models.Facility.objects.all(),
      widget=forms.CheckboxSelectMultiple,
    )


    
    

rooms/views.py

from django.views.generic import ListView, DetailView, View #View import
from django.shortcuts import render
from django.core.paginator import Paginator
from . import models, forms


class HomeView(ListView):

    """HomeView Definition"""

    model = models.Room
    paginate_by = 10
    paginate_orphans = 5
    ordering = "created"
    context_object_name = "rooms"


class RoomDetail(DetailView):

    """RoomDetail Definition"""

    model = models.Room


class SearchView(View):

    """SearchView Definition"""

    def get(self, request):

        country = request.GET.get("country")

        if country:

            form = forms.SearchForm(request.GET)

            if form.is_valid():

                city = form.cleaned_data.get("city")
                country = form.cleaned_data.get("country")
                room_type = form.cleaned_data.get("room_type")
                price = form.cleaned_data.get("price")
                guests = form.cleaned_data.get("guests")
                bedrooms = form.cleaned_data.get("bedrooms")
                beds = form.cleaned_data.get("beds")
                baths = form.cleaned_data.get("baths")
                instant_book = form.cleaned_data.get("instant_book")
                superhost = form.cleaned_data.get("superhost")
                amenities = form.cleaned_data.get("amenities")
                facilities = form.cleaned_data.get("facilities")

                filter_args = {}

                if city != "Anywhere":
                    filter_args["city__startswith"] = city

                filter_args["country"] = country

                if room_type is not None:
                    filter_args["room_type"] = room_type

                if price is not None:
                    filter_args["price__lte"] = price

                if guests is not None:
                    filter_args["guests__gte"] = guests

                if bedrooms is not None:
                    filter_args["bedrooms__gte"] = bedrooms

                if beds is not None:
                    filter_args["beds__gte"] = beds

                if baths is not None:
                    filter_args["baths__gte"] = baths

                if instant_book is True:
                    filter_args["instant_book"] = True

                if superhost is True:
                    filter_args["host__superhost"] = True

                for amenity in amenities:
                    filter_args["amenities"] = amenity

                for facility in facilities:
                    filter_args["facilities"] = facility

                qs = models.Room.objects.filter(**filter_args).order_by("-created")

                paginator = Paginator(qs, 10, orphans=5)

                page = request.GET.get("page", 1)

                rooms = paginator.get_page(page)

                return render(
                    request, "rooms/search.html", {"form": form, "rooms": rooms}
                )

        else:
            form = forms.SearchForm()

        return render(request, "rooms/search.html", {"form": form})
    

rooms/urls.py

from django.urls import path
from . import views

app_name = "rooms"

urlpatterns = [
    path("<int:pk>", views.RoomDetail.as_view(), name="detail"),
    path("search/", views.SearchView.as_view(), name="search"),
]
    

templates/rooms/search.html

{% extends "base.html" %}

{% block page_title %}
    Search
{% endblock page_title %}

{% block search-bar %}
{% endblock search-bar %}

{% block content %}

<h2>Search!</h2>

<form method="get" action="{% url "rooms:search" %}">
    {{form.as_p}} #p 태그처럼 사용하기
    <button>Search</button>
</form>

<h3>Results</h3>

{% for room in rooms %}
    <h3>{{room.name}}</h3>
{% endfor %}



{% endblock content %}
profile
블로그 이전했습니다. https://morethan-haseung-log.vercel.app

0개의 댓글