03_Web
20_페이지 구성 개선
chuuvelop
2025. 2. 19. 17:23
728x90
현재 포스트 목록 페이지의 문제점
- 대표 이미지가 없는 포스트가 하나라도 있으면 포스트 목록 페이지에서 오류가 발생
- 포스트의 본문 전체를 다 보여주는 데 장문의 포스트가 있으면 첫 페이지에서 원하는 게시글을 빠르게 찾기 어려움
- 본문 앞 부분만 보여주는 미리보기 기능 필요
조건에 따라 이미지 보이기
# blog/post_list.html
{% if p.head_image %}
<a href="#!">
<img class="card-img-top" src="{{ p.head_image.url }}" alt="{{ p }} head image" />
</a>
{% endif %}
- img 태그의 alt 속성 : 이미지를 보여줄 수 없을 때 이미지 대신 나타나게 하는 텍스트
- 제대로 웹사이트가 동작하고 있다면 필요없지만 만약의 경우에 대비해야함
이미지가 없을 경우 사용할 임의의 이미지 가져오기
- 로렘 픽숨 Lorem Picsum(https://picsum.photos/)
# blog/post_list.html
{% if p.head_image %}
<a href="#!">
<img class="card-img-top" src="{{ p.head_image.url }}" alt="{{ p }} head image" />
</a>
{% else %}
<img class="card-img-top" src="https://picsum.photos/800/200" alt="random_image"/>
{% endif %}
임의로 나타나는 이미지 고정하기
- 문제
- 임의의 이미지의 첫 번째 문제는 웹브라우저를 새로고침 할 때 마다 이미지가 바뀐다는 것
- 웹사이트를 방문하는 사람 입장에서는 새로운 게시글이 업로드 된 것으로 착각할 수 있음
- 두 번째 문제는 이미지 없는 게시글이 여러 개 있을 때 모두 똑같은 이미지를 보여준다는 것
- 임의의 이미지의 첫 번째 문제는 웹브라우저를 새로고침 할 때 마다 이미지가 바뀐다는 것
- 해결방법
- https://picsum.photos/seed/id값/ 을 입력하면 해당 id값을 가지는 위치에 매번 동일한 이미지를 나타냄
- 각 게시글마다 고유한 pk값을 가지기 때문에 id값 부분에 해당하는 게시글의 pk를 넣으면 고정된 결과를 얻을 수 있음
# blog/post_list.html
{% if p.head_image %}
<a href="#!">
<img class="card-img-top" src="{{ p.head_image.url }}" alt="{{ p }} head image" />
</a>
{% else %}
<img class="card-img-top" src="https://picsum.photos/seed/{{ p.id }}/800/200" alt="random_image"/>
{% endif %}
첨부파일이 있는 경우 다운로드 버튼 만들기
- file_upload 필드를 추가해 파일 첨부 기능을 구현했지만 현재는 관리자페이지에서만 확인 가능함
- if문을 사용해 첨부파일이 있는 경우에는 다운로드 버튼이 보이도록 템플릿을 수정
# blog/post_detail.html
<!-- Post content-->
<section class="mb-5">
<p class="fs-5 mb-4">{{ post.content }}</p>
{% if post.file_upload %}
<a href="{{ post.file_upload.url }}"
class="btn btn-outline-dark"
role="button" download>Download
</a>
{% endif %}
</section>
첨부파일명과 확장자 아이콘 나타내기
- 지금은 사용자가 어떤 파일을 다운받는지 알 수 없음
- models.py에서 파일명을 찾아내는 함수와 확장자를 찾아내는 함수를 개발
# blog/models.py
import os
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
head_image = models.ImageField(upload_to="blog/images/%Y/%m/%d/", blank=True)
file_upload = models.FileField(upload_to="blog/files/%Y/%m/%d/", blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"[{self.pk}]{self.title}"
# 이걸 설정해주면 관리자페이지에 VIEW ON SITE라는 버튼이 생김
def get_absolute_url(self):
return f"/blog/{self.pk}/"
def get_file_name(self):
return os.path.basename(self.file_upload.name)
def get_file_ext(self):
return self.get_file_name().split(".")[-1]
# blog/post_detail.html
<head>
...
<script src="https://kit.fontawesome.com/4c4232cd4f.js" crossorigin="anonymous"></script>
</head>
...
{% if post.file_upload %}
<a href="{{ post.file_upload.url }}"
class="btn btn-outline-dark"
role="button" download>Download:
{% if post.get_file_ext == "xlsx" or post.get_file_ext == "xls" %}
<!-- 엑셀 아이콘 -->
<i class="fa-solid fa-file-excel"></i>
{% elif post.get_file_ext == "docx" or post.get_file_ext == "doc" %}
<!-- 워드 아이콘 -->
<i class="fa-solid fa-file-word"></i>
{% else %}
<!-- 일반 파일 아이콘 -->
<i class="fa-solid fa-file-arrow-down"></i>
{% endif %}
{{ post.get_file_name}}
</a>
{% endif %}
템플릿 필터를 사용해 게시글 미리보기 기능 구현(...)
- 포스트 목록에서 본문 내용 전체를 보여줄 경우 본문이 너무 길다면 포스트 목록을 한 눈에 살펴보기 어려움
- 요약문이나 내용의 앞부분 일부만 보여주는 미리보기 기능을 장고에서 제공함
- truncatewords 또는 truncatechars를 사용
- truncatewords : 문자열을 단어 수 기준으로 자름
- truncatechars : 문자열을 글자 수 기준으로 자름
- truncatewords 또는 truncatechars를 사용
# blog/post_list.html
<div class="card-body">
<div class="small text-muted">{{ p.created_at }}</div>
<h2 class="card-title h4">{{ p.title }}</h2>
<p class="card-text">{{ p.content | truncatewords:45 }}</p>
<a class="btn btn-primary" href="{{ p.get_absolute_url }}">Read more →</a>
</div>
728x90