<도전 과제>
- 프론트엔드에서 카테고리별 게시글 목록 조회하기
<진행>
- 토대
- 파이썬 장고 심화 2주차, 3주차 때 살짝 했던 프론트엔드에서 시작한다
- 프론트엔드 프로젝트 - YouTube
- 이후 위 강의들을 쭉 들으면서 프론트엔드의 뼈대가 살짝 잡혔다
- 빈 화면에서 시작하면 백퍼 잘 못 할 것 같아서 위 강의를 통해 얻은 html, js를 그대로 우리 프로젝트 프론트엔드 폴더에 넣었다
- 그리고 백엔드랑 연결해 주는 작업을 했다 변수명이나 회원가입 시 들어가는 데이터 등 DRF프로젝트랑 다른 부분들이 있기 때문에 일일이 보면서 수정해줬다
- 약간의 고난이 있었지만 어쨌든 회원가입, 로그인, 로그아웃은 DRF프로젝트에서 한 거의 그대로를 썼다
- 카테고리별로 게시글 가져오기
- 일단 공부와 휴식 카테고리를 클릭했을 때 url에 study와 rest가 담겨서 그 url에서 study와 rest 부분을 빼온 다음 각 카테고리에 해당하는 게시글들을 불러와야겠다고 생각을 했다
- 그냥 단순한 생각으로는 공부나 휴식을 클릭했을 때 바로 study와 rest가 담겨서 게시글 불러오는 함수에 매개변수로 쓰고 싶었다
- 지금 다 구현하고 정리하고 있으려니까 왜 그게 안 됐는지 까먹었는데 여튼 안 됐다 아니 될 수도 있지만 나는 그 방법을 모르겠고 강의에서 알려준대로 한다
- 먼저 html에 공부 버튼과 휴식 버튼을 만들었다
- 드롭다운인 이유는 스터디를 눌렀을 때 바로 스터디 카테고리로 이동하는 게 아니라 전체 게시글 보기와 팔로잉 게시글 보기로 나눠야 하기 때문이다
...
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
study
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" id="study" onclick="handleClickCategory(this.id)">
전체 게시글보기</a></li>
<li><a class="dropdown-item" href="#">팔로잉 게시글 보기</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
rest
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" id="rest" onclick="handleClickCategory(this.id)">
전체 게시글보기</a></li>
<li><a class="dropdown-item" href="#">팔로잉 게시글 보기</a></li>
</ul>
</li>
...
- 전체 게시글 보기 부분에 onclick="handleClickCategory(this.id)"을 넣었다
- url에 study와 rest를 담을 것이므로 id값을 지정하고 매개변수로 id값이 들어가게끔 했다
// 공부 or 휴식 게시판 클릭 시 html에 있는 카테고리 이름을 가져와서 postCategory 함수를 실행함
function handleClickCategory(e) {
const categoryName = e
console.log(categoryName)
postCategory(categoryName);
}
- 핸들클릭카테고리 함수를 정의했다
- categoryName에 html에서 받아온 id값을 담는다
- 공부 클릭했을 때 study가 들어가고 휴식 클릭했을 때 rest가 들어간다
- 콘솔로그를 통해 원하는 값이 categoryName에 들어갔음을 확인했다
- 이제 categoryName에 들어있는 study는 postCategory() 함수의 매개변수로 들어간다
// url에 카테고리 이름을 담기 위한 작업
function postCategory(category_name) {
window.location.href = `${frontend_base_url}/posts/post_list.html?category=${category_name}`
}
- 이 함수는 url에 카테고리명을 담기 위한 함수다
- window.location.href를 통해 위 url로 이동하게 된다
- 현재 동작은 위 빨간 네모 부분을 클릭했을 때 일어나는 과정이다
// 카테고리별 게시글 리스트 보기
window.onload = async function loadPosts() {
// url에서 카테고리 이름을 가져옴
const urlParams = new URLSearchParams(window.location.search);
const categoryName = urlParams.get("category");
console.log(categoryName)
// 카테고리 이름을 매개변수로 백엔드에서 해당 카테고리의 글들을 가져옴
posts = await getPosts(categoryName)
console.log(posts)
// 게시글 목록 UI
const postCategoryList = document.getElementById("post-category-list")
// 불러온 게시글들을 하나씩 카드 형식으로 붙이는 작업
posts.forEach(post => {
const newCol = document.createElement("div");
newCol.setAttribute("class", "col")
newCol.setAttribute("onclick", `postDetail(${post.pk})`)
const newCard = document.createElement("div")
newCard.setAttribute("class", "card h-100")
newCard.setAttribute("id", `post-${post.pk}`)
newCol.appendChild(newCard)
const postImage = document.createElement("img")
postImage.setAttribute("class", "card-img-top")
if (post.image) {
postImage.setAttribute("src", `${backend_base_url}${post.image}`)
} else {
postImage.setAttribute("src", "https://cdn11.bigcommerce.com/s-1812kprzl2/images/stencil/original/products/426/5082/no-image__12882.1665668288.jpg?c=2")
}
newCard.appendChild(postImage)
const newCardBody = document.createElement("div")
newCardBody.setAttribute("class", "card-body")
newCard.appendChild(newCardBody)
const newCardTile = document.createElement("h5")
newCardTile.setAttribute("class", "card-title")
newCardTile.innerText = post.title
newCardBody.appendChild(newCardTile)
postCategoryList.appendChild(newCol)
});
}
- 백엔드에서 게시글들을 가져오는 함수인 getPosts()는 다음과 같다
// 카테고리별 게시글 조회
async function getPosts(categoryName) {
const response = await fetch(`${backend_base_url}/posts/category/${categoryName}/`)
console.log(response)
if (response.status == 200) {
const response_json = await response.json()
return response_json
} else {
alert("불러오는 데 실패했습니다")
}
}
- 백엔드에서 지정한 url을 부르면 나오는 response를 json 형태로 바꿔서 반환한다
- 이렇게 카테고리별 게시글 목록 보기가 완성됐다
- 이미지 엑박 오류
- 위 캡쳐를 보면 알겠지만 문제가 있다
- 이미지가 없는 게시글은 대체 이미지가 잘 나오고 있는데 정작 이미지를 넣은 게시글은 이미지가 안 나온다
- 도대체 뭐가 문제인걸까...
- 이미지 주소도 맞게 잘 인식하고 있는 것을 확인할 수 있었다
- DRF에서는 잘만 되던 게 우리 프로젝트에서는 안 된다..
- 주소를 직접 쳐서 들어가니 이런 오류가 나온다
- 원래 나와야 하는데....하면서 화면을 뚫어지게 보다가 알았다
- url 설정이 안 되어 있다...!!!
- 이미지 업로드 부분은 다른 팀원분이 하신 건데 settings.py에만 경로를 알려주고 정작 urls.py에는 경로 설정을 안 한 것이었다..! (이렇게 말하는 게 맞나...? 여튼 이미지 업로드 하면 정해둔 폴더에 잘 저장이 되는데 이렇게 page not found가 뜬 건 urls.py가 문제였던 것이었다)
# 프로젝트폴더/urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('posts/', include('posts.urls')),
path('users/', include('users.urls')),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # 바로
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROO) # 이 부분!
- 아래 2줄이 추가되어 있지 않아서 발생한 문제였다
- 추가하고 새로고침하니 이미지가 제대로 나오는 걸 확인할 수 있었다!!
- 게시글 pk 값이 undefined 되는 문제
- 문제가 더 있었다
- 게시글 목록을 차곡차곡 붙일 때 게시글을 클릭하면 상세페이지를 여는 함수가 실행되게끔 코드를 짰다
...
posts.forEach(post => {
const newCol = document.createElement("div");
newCol.setAttribute("class", "col")
newCol.setAttribute("onclick", `postDetail(${post.pk})`)
const newCard = document.createElement("div")
newCard.setAttribute("class", "card h-100")
newCard.setAttribute("id", `post-${post.pk}`)
newCol.appendChild(newCard)
...
- 바로 이 부분이다
- 이렇게 게시글의 pk값이 상세게시글 함수의 매개변수로 들어가고, 해당 게시글 목록의 id가 되게끔 했는데 콘솔창을 보니 undefined가 뜨는 거다...딥빡....
- 안습 콘솔창,,,,
- 숫자가 나와야 하는데...왜........
- 역시 고민에 고민에 고민을 하다가 post를 콘솔에 찍어봤다
- 또 뚫어져라 봤다..
- 마침내 깨달았다
- 백엔드에서 보내는 게시글 정보에 pk값이 없다..!!!!
- 게시글 목록은 postListSerializer를 통해 보내는데
# posts/serializers.py
...
class PostListSerializer(serializers.ModelSerializer):
category = serializers.SerializerMethodField()
user = serializers.SerializerMethodField()
like = serializers.StringRelatedField(many=True)
def get_category(self, obj):
return obj.category.name
def get_user(self, obj):
return obj.user.username
class Meta:
model = Post
fields = ("category", "user", "title", "content",
"image", "star", "like", "updated_at",)
...
- 필요없는 값을 제외하고 수동으로 필드를 가져오다 보니 pk값을 빠뜨린거다...!
# posts/serializers.py
...
fields = ("pk", "category", "user", "title", "content",
"image", "star", "like", "updated_at",)
...
- 이렇게 pk값을 추가하고 다시 새로고침 해서 보니까
- 휴 드디어 제대로 나온다...
- 짜릿......
- 이렇게 겨우 하나를 구현했다....이래서 언제 다 하지..?
- 팔로잉 게시글 모아보기, 카테고리별로 글쓰기 버튼 따로 놓고 카테고리에 따라 게시글에 카테고리 자동 저장되게끔 하기....가 남아 있다....
- 근데 사실 하나만 한 건 아니다 프론트엔드 강의 들으면서 하다보니 회원가입, 로그인, 로그아웃은 얼결에 후루룩 해냈으니..!! 사실상 4개 구현한거지!!