ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • django update profile by CBV
    Project using python/Cloning Airbnb 2021. 3. 5. 10:06

    url 설정

    config/urls.py

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

    users/urls.py

    from django.urls import path
    from . import views
    
    app_name = "users"
    
    urlpatterns = [path(
            "<int:pk>/update-profile/",
            views.UpdateProfileView.as_view(),
            name="update-profile",
        )]
    

    {% url %}

      userDetail.html의 일부다. Edit Profile button을 누르면 profile을 수정할 수 있는 page로 간다. url template tag를 이용해서 update_profile page로 갈 수 있게 한다. {% url 'users:update-profile' user.pk %}는 /users/<int:pk>/update-profile/과 같다.

    CBV(Class Based View)

    users/views.py

      CBV는 django에서 정의한 여러가지 View들을 이용한다. 그 중 UpdateView를 이용해서 update profile page를 작성한다. UpdateView는 FormView와는 다르게 forms.py를 작성하지 않고도 View 안에서 fields를 정의할 수 있다. 아니 정의해야만 rendering이 가능하다.

      get_form method를 이용해서 form의 속성을 제어할 수 있다.

    from django.views.generic import UpdateView
    from . import mixins
    
    
    class UpdateProfileView(mixins.LoginOnlyView, mixins.EmailLoginOnlyView, UpdateView):
        model = models.User
        fields = {
            "avatar",
            "first_name",
            "last_name",
            "email",
            "gender",
            "language",
            "currency",
            "birthdate",
            "superhost",
            "bio",
        }
        template_name = "pages/users/update_profile.html"
        success_message = "Profile Updated"
    
        def get_form(self, form_class=None):
            form = super().get_form(form_class=form_class)
            form.fields["email"].widget.attrs = {"placeholder": "Email"}
            form.fields["first_name"].widget.attrs = {"placeholder": "First name"}
            form.fields["last_name"].widget.attrs = {"placeholder": "Last name"}
            form.fields["bio"].widget.attrs = {"placeholder": "Bio"}
            return form
    

    users/models.py

      UpdateView는 user가 profile을 성공적으로 update 했을 때 redirect가 될 url이 필요하다. models.py에서 get_absolute_url() method를 만들면, 해당 url로 redirect가 된다. redirect 대신 reverse를 사용한 이유는 kwargs 인자를 전달하기 위해서다. kwargs로 pk 값을 전달해야 하는데, redirect는 이것이 불가능 하다.

        def get_absolute_url(self):
            return reverse("users:profile", kwargs={"pk": self.pk})

    users/mixins.py

      UpdateView가 상속하는 mixins다. mixins는 Route 보안을 담당한다.

    from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
    from django.contrib import messages
    from django.urls import reverse_lazy
    from django.shortcuts import redirect, reverse
    
    
    class LoginOnlyView(LoginRequiredMixin):
        login_url = reverse_lazy("users:login")
    
    
    class EmailLoginOnlyView(UserPassesTestMixin):
    
        permission_denied_message = "Page Not Found"
    
        def test_func(self):
            return self.request.user.login_method == "email"
    
        def handle_no_permission(self):
            messages.error(self.request, "Can't go there")
            return redirect(reverse("core:home"))
    

    templates

    pages/users/update_profile.html

      코드 길이는 달라지지 않았다. 물론 {{form}} 한 줄로 <form><form/> 안을 압축할 수 있지만 제어를 하기 위해서 일일이 {{form.*}}로 했다.

    {% extends 'base.html' %}
    
    
    {% block page_title %}
      Edit {{user.first_name}}'s Profile
    {% endblock page_title %}
    
    {% block search-bar %}
    <div></div>
    {% endblock search-bar %}
    
    {% block content %}
      <div class="background">
        <div class="wrap">
          <div class="flex flex-col items-center justify-center">
            <div class="mb-4">
              {% include 'mixins/avatar.html' with user=user %}
            </div>
            {% if user.login_method == "github" %}
              <div class="flex items-center mb-4">
                <h3 class="font-bold text-base mr-2">Github Email:</h3>
                <span>{{user.email}}</span>
              </div>
            {% elif user.login_method == "kakao" %}
              <div class="flex items-center mb-4">
                <h3 class="font-bold text-base mr-2">Kakao Email:</h3>
                <span>{{user.email}}</span>
              </div>
            {% endif %}
          </div>
          <form method="post" class="form" enctype="multipart/form-data">
            {% csrf_token %}
            <div class="form_input rounded-tl-lg rounded-tr-lg">
              <label for="first_name">First Name</label>
              {{form.first_name}}
            </div>
    
            <div class="form_input">
              <label for="last_name">Last Name</label>
              {{form.last_name}}
            </div>
    
              {% if user.login_method == "email" %}
                <div class="form_input">
                  <label for="email">Email</label>
                  {{form.email}}
                </div>
              {% endif %}
    
            {% if user.login_method == "email" %}
              <div class="form_input">
                <label for="avatar">Avatar</label>
                <input type="file" id="avatar" name="avatar" accept="image/*">
              </div>
            {% endif %}
    
            <div class="select">
              <label for="gender">Gender</label>
              {{form.gender}}
            </div>
    
            <div class="select">
              <label for="language">Language</label>
              {{form.language}}
            </div>
            
            <div class="select">
              <label for="currency">Currency</label>
              {{form.currency}}
            </div>
    
            <div class="birthdate">
              <label for="birthdate">Birthdate</label>
              <input type="date" id="birthdate" name="birthdate" placeholder="Birthdate" value="{{user.birthdate|date:'Y-m-d'}}" required>
            </div>
    
            <div class="form_input rounded-br-lg rounded-bl-lg">
              <textarea id="bio" placeholder="Bio" name="bio">{{user.bio}}</textarea>
            </div>
            <button class="form_button">Edit Profile</button>
          </form>
          {% if user.login_method == 'email' %}
            <button class="button bg-red-500">
              <a href="#">Change Password</a>
            </button>
          {% endif %}
          <button class="button bg-gray-700">
            <a href="{% url 'users:profile' user.pk %}">Back</a>
          </button>
        </div>
      </div>
    
    {% endblock content %}
      

    참고 자료

    • 노마드 코더의 Airbnb 클론 강의
    • UpdateView

    소스 코드

    github.com/zpskek/airbnb-clone-v3/commit/f35e672a49555e4a0c5f9c037d34391bb3406bdf

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

    django change password by CBV  (0) 2021.03.05
    django change password by FBV  (0) 2021.03.05
    django Update Profile by FBV  (0) 2021.03.05
    django user profile CBV  (0) 2021.03.04
    django user profile FBV  (0) 2021.03.04

    댓글

Designed by Tistory.