파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 강의를 듣고 정리한 글입니다.
이번 포스팅에서는 post_detail을 구현한다. 사실 앞서 설명했던 내용이 반복된다.
하지만 일반적으로 detail을 구현할 때 이러한 패턴을 반복적으로 적용이 가능할 거 같아서 포스팅을 하기로 했다.
다음과 같이 진행하면 될 것 같다.
포스트 작성 후의 url 리디렉션 시 get_absolute_url을 활용하도록 수정했다. (get_absolute_url 포스팅 참고)
detail 뷰를 구현했다.
# instagram/views.py
@login_required
def post_new(request):
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
post.tag_set.add(*post.extract_tag_list()) # 실제 PK가 있어야 하므로 post를 저장후에 수행한다.
messages.success(request, '포스팅을 저장했습니다.')
return redirect(post) # get_absolute_url 정의 시 해당 URL로 리디렉션된다.
else:
form = PostForm()
return render(request, 'instagram/post_form.html', {
'form': form,
})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'instagram/post_detail.html', {
'post': post,
})
# instagram/urls.py
from django.urls import path
from . import views
app_name = 'instagram'
urlpatterns = [
# ...
path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
detail을 추가했다면 get_absolute_url
을 정의하자.
# instagram/models.py
class Post(models.Model):
# ...
def get_absolute_url(self):
return reverse('instagram:post_detail', args=[self.pk])
name property: 템플릿이나 백엔드 코드에서 post.author.name
등과 같이 바로 활용이 가능하다.
avatar_url property: 원래 layout.html에 템플릿으로 분기가 쳐져 있었으나, 여러 템플릿에서 이 로직을 활용 할 것 같아서 모델의 프로퍼티로 리팩터링 했다.
name, avatar_url 프로퍼티 모두 아래 템플릿에서 활용한다.
class User(AbstractUser):
# ...
@property
def name(self):
return f'{self.first_name} {self.last_name}'
@property
def avatar_url(self):
if self.avatar:
return self.avatar.url
else:
return resolve_url('pydenticon_image', self.username)
# ...
instagram/templates/instagram/post_detail.
{% extends 'instagram/layout.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<img src="{{ user.avatar_url }}" style="width: 32px; height: 32px">
{{ post.author.name }}
</div>
<div class="card-body">
<img src="{{ post.photo.url }}" alt="" style="width: 100%;">
</div>
<div class="card-footer">
{% for tag in post.tag_set.all %}
<span class="badge badge-primary">
#{{ tag.name }}
</span>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}