일반적인 detail 구현 패턴

guava·2022년 1월 3일
0
post-custom-banner

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 강의를 듣고 정리한 글입니다.

이번 포스팅에서는 post_detail을 구현한다. 사실 앞서 설명했던 내용이 반복된다.

하지만 일반적으로 detail을 구현할 때 이러한 패턴을 반복적으로 적용이 가능할 거 같아서 포스팅을 하기로 했다.

다음과 같이 진행하면 될 것 같다.

  1. view를 작성한다.
  2. urls.py에 path를 추가한다.
  3. 해당 get_absolute_url을 작성한다.
  4. 템플릿을 작성한다.


포스트 작성 후의 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'),
]

모델


Post 모델

detail을 추가했다면 get_absolute_url을 정의하자.

# instagram/models.py

class Post(models.Model):
    # ...

    def get_absolute_url(self):
        return reverse('instagram:post_detail', args=[self.pk])

User 모델

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 %}
post-custom-banner

0개의 댓글