-
django Update Profile by FBVProject using python/Cloning Airbnb 2021. 3. 5. 09:22
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.updateProfile, 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/과 같다.
FBV(Function Based View)
users/views.py
FBV에서는 if 문으로 GET method 요청이 왔을 때와 POST method 요청이 왔을 때를 구분한다. GET은 page를 보여주고 POST는 client로부터 온 data를 처리한다.
# users/views.py from django.shortcuts import render, redirect, reverse from django.contrib import messages from .exception import VerifyUser @login_required def updateProfile(request, pk): if request.method == "GET": try: if request.user.pk != pk: raise VerifyUser("Page Not found") user = models.User.objects.get_or_none(pk=pk) if user is None: messages.error(request, "User does not exist") return redirect(reverse("core:home")) genders = models.User.GENDER_CHOICES languages = models.User.LANGUAGE_CHOICES currencies = models.User.CURRENCY_CHOICES login_methods = models.User.LOGIN_CHOICES choices = { "genders": genders, "languages": languages, "currencies": currencies, "login_methods": login_methods, } return render( request, "pages/users/update_profile.html", context={"user": user, **choices}, ) except VerifyUser as error: messages.error(request, error) return redirect("core:home") return render(request, "pages/users/update_profile.html", {"user": user}) elif request.method == "POST": try: if request.user.pk != pk: raise VerifyUser("Page Not found") user = models.User.objects.get_or_none(pk=pk) if user is None: messages.error(request, "User does not exist") return redirect(reverse("core:home")) avatar = request.FILES.get("avatar") if avatar is not None and avatar != "": user.avatar = avatar first_name = request.POST.get("first_name") if first_name is not None: user.first_name = first_name last_name = request.POST.get("last_name") if last_name is not None: user.last_name = last_name email = request.POST.get("email") if email is not None: user.email = email gender = request.POST.get("gender") if gender is not None: user.gender = gender language = request.POST.get("language") if language is not None: user.language = language currency = request.POST.get("currency") if currency is not None: user.currency = currency birthdate = request.POST.get("birthdate") if birthdate is not None: user.birthdate = birthdate superhost = bool(request.POST.get("superhost")) if superhost is not None: user.superhost = superhost bio = request.POST.get("bio") if bio is not None: user.bio = bio user.save() messages.success(request, f"{user.email} profile update succeded") return redirect(reverse("users:profile", kwargs={"pk": pk})) except VerifyUser as error: messages.error(request, error) return redirect("core:home")
templates
pages/users/update_profile.html
<form> tag에 enctype="multipart/form-data" attribute가 있다. django가 file을 업로드할 때 사용하는 속성이다. views.py에서는 request.FILES.get()으로 업로드하는 file에 접근할 수 있다.
{% csrf_token %}은 csrf 공격을 막기 위한 token이다. django는 보안이 뛰어나기 때문에 {% csrf_token %} tag를 사용하지 않으면 submit이 안 된다. csrf 공격의 보안은 절대 client를 신뢰하지 않는 것으로 시작한다. 즉, 이 token 값을 가지지 않은 브라우저 요청은 받아들이지 않는다.
{% 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> <input type="text" id="first_name" placeholder="First Name" value="{{user.first_name}}" name="first_name"> </div> <div class="form_input"> <label for="last_name">Last Name</label> <input type="text" id="last_name" placeholder="Last Name" value="{{user.last_name}}" name="last_name"> </div> {% if user.login_method == "email" %} <div class="form_input"> <label for="email">Email</label> <input type="text" id="email" placeholder="Email" value="{{user.email}}" name="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> <select name="gender" id="gender"> {% for key, value in genders %} <option value="{{value}}" {% if value == user.gender %}selected{% endif %}> {{value}} </option> {% endfor %} </select> </div> <div class="select"> <label for="language">Language</label> <select name="language" id="language"> {% for key, value in languages %} <option value="{{value}}" {% if value == user.language %}selected{% endif %}> {{value}} </option> {% endfor %} </select> </div> <div class="select"> <label for="currency">Currency</label> <select name="currency" id="currency"> {% for key, value in currencies %} <option value="{{value}}" {% if value == user.currency %}selected{% endif %}> {{value}} </option> {% endfor %} </select> </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 클론 강의
- file upload
- {% csrf_token %}
소스 코드
github.com/zpskek/airbnb-clone-v3/commit/c3862c66c02bf1bdac912cb592768d9536584777
'Project using python > Cloning Airbnb' 카테고리의 다른 글
django change password by FBV (0) 2021.03.05 django update profile by CBV (0) 2021.03.05 django user profile CBV (0) 2021.03.04 django user profile FBV (0) 2021.03.04 django mailgun.com 연동(interlocking) (0) 2021.03.04