ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • django update-review with axios
    Project using python/Cloning Airbnb 2021. 3. 18. 09:10

    url 설정

    config/urls.py

    urlpatterns = [
        path("reviews/", include("reviews.urls", namespace="reviews"))
    ]

    reviews/urls.py

    from django.urls import path
    from reviews import views
    
    app_name = "reviews"
    
    urlpatterns = [
            path("<int:room_pk>/<int:review_pk>/update/", views.updateReview, name="update")
        ]
    

    Client

    review.html

    <div class="grid grid-cols-2 gap-x-52 gap-y-3 mb-10">
    {% for review in room.reviews.all %}
        <div>
            <div class="flex justify-between items-center">
                <div class="flex items-center mb-4">
                    {% if review.user.avatar %}
                    <a href="{% url 'users:profile' review.user.pk%}">
                        <img src="{{review.user.avatar.url}}" class="img w-16 h-16 mr-4" alt="User avatar" title="User Avatar">
                    </a>
                    {% else %}
                    <a href="{% url 'users:profile' review.user.pk%}">
                        <div class="img w-16 h-16 mr-4">{{review.user.first_name|first|upper}}</div>
                    </a>
                    {% endif %}
                    <div class="flex flex-col">
                        <span class="font-bold">{{review.user|capfirst}}</span>
                        <span class="text-sm text-gray-400">{{review.created}}</span>
                    </div>
                </div>
                {% if review.user == user %}
                    <div class="w-24">
                        <button class="reviewAmend review_button bg-blue-600 mt-0">Update</button>
                        <button id="reviewDelete" class="review_button bg-red-600 mt-3">Delete</button>
                    </div>
                {% endif %}
            </div>
            <p class="mb-4 font-normal" name="{{review.pk}}">{{review.review}}</p>
        </div>
    {% endfor %}
    </div>

    assets/js/updateReview.js

      django는 form을 post로 server에 submit할 때 무조건 csrf token이 필요하다. .html file에서는 {% csrf_token %}을 추갛면 되지만 JS에서 axios로는 그것이 불가능하다. axios를 이용해서 form을 제출하고 싶다면 다음과 같이 axios.defaults.xsrfCookeName과 axios.defaults.xsrfHeaderName을 추가해줘야 한다.

    import axios from "axios";
    
    axios.defaults.xsrfCookieName = "csrftoken";
    axios.defaults.xsrfHeaderName = "X-CSRFToken";
    
    const reviewAmends = document.querySelectorAll(".reviewAmend");
    
    const handleAmendInput = (event) => {
      event.preventDefault();
      const room_pk = window.location.href.split("/")[4];
      const form = event.target;
      const p = form.parentNode;
      const updateBtn =
        p.previousSibling.previousSibling.childNodes[3].childNodes[1];
      const reviewNode = p.parentNode;
      const textarea = form.querySelector("textarea");
      const text = textarea.value;
      const review_pk = reviewNode.id;
    
      p.innerHTML = text;
    
      updateBtn.addEventListener("click", handleAmend);
      updateBtn.classList.remove("hidden");
    
      axios({
        method: "POST",
        url: `/reviews/${room_pk}/${review_pk}/update/`,
        data: {
          review: text,
        },
      });
    };
    
    const handleAmend = (e) => {
      const btn = e.target;
      const btnParent = btn.parentNode.parentNode;
      const p = btnParent.nextSibling.nextSibling;
      const form = document.createElement("form");
      const textarea = document.createElement("textarea");
      const div = document.createElement("div");
      const submit = document.createElement("button");
    
      btn.removeEventListener("click", handleAmend);
      btn.classList.add("hidden");
    
      textarea.value = p.innerText;
      textarea.classList.add(
        "w-full",
        "h-20",
        "mb-2",
        "resize-none",
        "border",
        "border-black",
        "p-1",
        "rounded-lg"
      );
      p.innerText = "";
    
      div.classList.add("flex", "justify-end");
    
      submit.innerText = "Amend";
      submit.classList.add("review_button", "w-32", "bg-blue-600");
    
      div.append(submit);
    
      form.appendChild(textarea);
      form.appendChild(div);
    
      p.appendChild(form);
      p.childNode = form;
    
      form.addEventListener("submit", handleAmendInput);
    };
    
    const init = () => {
      if (reviewAmends) {
        reviewAmends.forEach((reviewAmend) => {
          reviewAmend.addEventListener("click", handleAmend);
        });
      }
    };
    
    init();
    

    FBV(Function Based View)

    reviews/views.py

      django에서 Client가 전달하는 post 값은 request.POST.get()으로 받을 수 있는데 request.POST는  form-encoded data만 가능하다. JSON 형식으로 request가 오면 request.body를 사용해야 한다.  먼저 json을 import하고 json.loads()를 통해서 문자열로온 json을 dict으로 바꿔주자. 참고로 server에서 client로 보낼 때 직렬화 과정을 거치는데, 이 때는 json.dumps()를 사용해서 dict을 string으로 직렬화한다. json.loads는 직렬화 된 json을 다시 dict로 바꿔주는 method다.

    # reviews/views.py
    
    import json
    
    from django.shortcuts import redirect, reverse
    from django.contrib import messages
    from django.http import HttpResponse
    
    from reviews import models as review_models
    from reservations import models as reservation_models
    
    
    def updateReview(request, room_pk, review_pk):
        review = review_models.Review.objects.get_or_none(pk=review_pk)
        if review is None:
            messages.error(request, "Review doesn't exist")
    
        content = json.loads(request.body.decode("utf-8"))
        text = content["review"]
        review.review = text
        review.save()
    
        return HttpResponse(200)

    참고 자료

    소스 코드

    github.com/zpskek/airbnb-clone-v3/commit/86d27058d4ed507d8ed0f00addb62f4c6df9baaa

    'Project using python > Cloning Airbnb' 카테고리의 다른 글

    django toggle-list by FBV  (0) 2021.04.23
    django delete-review by FBV with axios  (0) 2021.03.18
    django create-review by FBV  (0) 2021.03.18
    django cancel reservation by FBV  (0) 2021.03.17
    django confirm reservation by FBV  (0) 2021.03.17

    댓글

Designed by Tistory.