1. ProfileUpdateView
ProfileUpdateView 생성
createView와 거의 동일하게 생성한다.
views.py 일부
class ProfileUpdateView(UpdateView):
model = Profile
context_object_name = 'target_profile'
form_class = ProfileCreationForm
success_url = reverse_lazy('accountapp:hello_world')
template_name = 'profileapp/update.html'
update.html
enctype을 추가해주었다.
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block content %}
<div style="text-align: center; max-width: 500px; margin: 4rem auto">
<div class="mb-4">
<h4>Update Profile</h4>
</div>
<form action="{% url 'profileapp:update' pk=target_profile.pk %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
</form>
</div>
{% endblock %}
urls.py
app_name = 'profileapp'
urlpatterns = [
path('create/', ProfileCreateView.as_view(), name='create'),
path('update/<int:pk>', ProfileUpdateView.as_view(), name='update'),
]
accoutnapp/detail.html의 일부
profile update 페이지로 이동할 수 있는 링크를 추가해준다.
{% if target_user.profile %}
<p>
{{ target_user.profile.nickname }}
<a href="{% url 'profileapp:update' pk=target_user.profile.pk %}">
edit
</a>
</p>
결과 화면
이미지 파일 표시하기
프로필 페이지에 이미지를 표시해본다. 부가적으로 메시지도 추가한다.
accoutnapp/detail.html 일부
{% if target_user.profile %}
<img src="{{ target_user.profile.image.url }}" alt=""
style="height: 10rem; width: 10rem; border-radius: 20rem; margin-bottom: 2rem;">
<p>
{{ target_user.profile.nickname }}
<a href="{% url 'profileapp:update' pk=target_user.profile.pk %}">
edit
</a>
<h6>
{{ target_user.profile.message }}
</h6>
</p>
static url 추가
단순히 img 태그만 추가하면 이미지 파일이 보이지 않는다. 이것은 이미지 파일 등 정적 리소스 파일에 대한 라우팅을 해주지 않아서이다. prgmatic/urls.py에 +static으로 MEDIA 파일들에 대한 라우팅 설정을 추가한다.
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accountapp.urls')),
path('profiles/', include('profileapp.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
static 모듈의 위치는 django.conf.urls.static이다.
프로필 이미지까지 추가되었다.
Decorator 처리
profile에도 인증 정보를 검사하는 decorator를 추가한다. accountapp에서 복사해와서 약간만 변경한다. 본인의 profile만 수정할 수 있도록 하기 위해서 profile.user가 request.user와 일치하는지 검사한다.
profileapp/decorators.py
from django.contrib.auth.models import User
from django.http import HttpResponseForbidden
from profileapp.models import Profile
def profile_ownership_required(func):
def decorated(request, *args, **kwargs):
profile = Profile.objects.get(pk=kwargs['pk'])
if not profile.user == request.user:
return HttpResponseForbidden()
return func(request, *args, **kwargs)
return decorated
profileapp/views.py 일부
@method_decorator(profile_ownership_required, 'get')
@method_decorator(profile_ownership_required, 'post')
class ProfileUpdateView(UpdateView):
model = Profile
context_object_name = 'target_profile'
form_class = ProfileCreationForm
success_url = reverse_lazy('accountapp:hello_world')
template_name = 'profileapp/update.html'
2. 리팩토링
마무리 작업으로 리팩토링을 한다.
success_url 수정 : 동적 redirect url 적용
일단 프로필 생성 또는 수정 후 홈페이지로 이동하도록 reverse_lazy('accoutnapp:hello_world')로 지정해놨는데, 실제로는 detail 페이지로 이동하는 것이 상식적이다. 이를 위해서 success_url을 변경해야한다.
그런데 detail 페이지는 profile의 pk 값을 받도록 되어있으므로 단순히 reverse_lazy로 redirect가 어렵다. 이를 위해서 get_success_url 메서드를 오버라이딩한다. 기존 각 View 아래에 있던 success_url 속성은 제거한다.
profileapp/views.py
class ProfileCreateView(CreateView):
model = Profile
context_object_name = 'target_profile'
form_class = ProfileCreationForm
template_name = 'profileapp/create.html'
def form_valid(self, form):
#생략
def get_success_url(self):
return reverse('accountapp:detail', kwargs={'pk': self.object.user.pk})
@method_decorator(profile_ownership_required, 'get')
@method_decorator(profile_ownership_required, 'post')
class ProfileUpdateView(UpdateView):
#생략
def get_success_url(self):
return reverse('accountapp:detail', kwargs={'pk': self.object.user.pk})
프로필 수정 인증 처리
마지막으로 프로필을 변경할 수 있는 create, edit 버튼은 로그인 사용자가 프로필의 주인일때만 노출되도록 설정한다.(아래 코드에서 ### 사이 부분만)
accountapp/detail.html
{% if target_user.profile %}
<img src="{{ target_user.profile.image.url }}" alt=""
style="height: 12rem; width: 12rem; border-radius: 20rem; margin-bottom: 2rem;">
<p>
{{ target_user.profile.nickname }}
###
{% if target_user == user %}
<a href="{% url 'profileapp:update' pk=target_user.profile.pk %}">
edit
</a>
{% endif %}
###
<h5 style="margin-bottom: 3rem;">
{{ target_user.profile.message }}
</h5>
</p>
{% else %}
###
{% if target_user == user %}
<a href="{% url 'profileapp:create' %}">
<h2 style="font-family: 'NanumSquareB'">
Create Profile
</h2>
</a>
{% else %}
<h2>
닉네임 미설정
</h2>
{% endif %}
###
{% endif %}
참조
1. 작정하고 장고! Django로 Pinterest 따라만들기 : 바닥부터 배포까지-박형석님 인프런 강의
'Programming-[Backend] > Django' 카테고리의 다른 글
Django로 Pinterest 따라 만들기-12. ListView/Pagination, Mixin, CommentApp 구현 (0) | 2022.06.11 |
---|---|
Django로 Pinterest 따라 만들기-11. MagicGrid 활용, ArticleApp CRUD 완성하기 (0) | 2022.06.10 |
Django로 Pinterest 따라 만들기-9. ModelForm 사용, Profileapp 구현 (0) | 2022.06.09 |
Django로 Pinterest 따라 만들기-8. Authentication, Decorator 활용, superuser 및 media 설정 (0) | 2022.06.09 |
Django로 Pinterest 따라 만들기-7. Update, DeleteView 구현 (0) | 2022.06.09 |