이번 단계에서는 웹사이트의 대문인 메인 페이지를 만듭니다.
로그인한 사용자가 접속했을 때 "내가 쓴 글", "내 댓글", "좋아요 한 글"을 한눈에 볼 수 있는 대시보드(Dashboard) 형태로 구현해 보겠습니다.
[STEP 5] 메인 페이지 구현 (대시보드 & 데이터 조회)
지금까지는 http://127.0.0.1:8000/board/free/ 처럼 긴 주소를 입력해야 게시판에 들어갈 수 있었습니다.
이제 사이트의 대문인 메인 페이지(Root URL)를 만들어 보겠습니다.
단순히 게시판 목록만 보여주는 것이 아니라, 로그인한 사용자에게 "나의 활동 내역"과 "커뮤니티 인기글"을 한눈에 보여주는
대시보드(Dashboard) 형태로 구현합니다.
1. 설정 추가 (config/settings.py)
메인 페이지는 로그인한 사람을 위한 공간입니다.
Django에게 "로그인이 필요한 페이지에 접근하면 어디로 보낼지", 그리고 "로그인/로그아웃 후에는 어디로 이동할지" 알려줘야 합니다.
config/settings.py 맨 아래에 다음 코드를 추가하세요.
# [추가] 로그인/로그아웃 관련 URL 설정
# @login_required가 걸린 뷰에 접근했을 때 이동할 로그인 페이지 주소
LOGIN_URL = '/accounts/login/'
# 로그인 성공 후 이동할 기본 주소 (루트 URL)
#LOGIN_REDIRECT_URL = '/board/free/'
LOGIN_REDIRECT_URL = '/'
# 로그아웃 후 이동할 주소
LOGOUT_REDIRECT_URL = '/accounts/login/'
2. URL 연결 (config/urls.py)
사이트의 가장 기본 주소(http://127.0.0.1:8000/)로 접속했을 때 보여줄 뷰를 연결합니다.
config/urls.py를 수정하세요.
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from boards import views as board_views # [추가] boards 앱의 views import
urlpatterns = [
# [추가] 루트 URL ('')을 home 뷰와 연결 -> 이름은 'home'
path('', board_views.home, name='home'),
path('admin/', admin.site.urls),
path('board/', include('boards.urls')),
path('accounts/', include('accounts.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
3. 로직 작성 (boards/views.py)
메인 화면에 뿌려줄 데이터를 준비합니다.
Django ORM을 활용하여 복잡한 SQL 없이도 내 활동과 인기글을 쉽게 가져올 수 있습니다.
boards/views.py 상단에 home 함수를 추가하세요.
# ... 기존 imports ...
from .models import Board, Post, Comment # [확인] Comment 모델 import 필수!
# [추가] 메인 페이지 (대시보드)
@login_required
def home(request):
# --- [섹션 1] 나의 활동 내역 ---
# 1. 내가 쓴 글 (최신순 5개)
my_posts = Post.objects.filter(author=request.user).order_by('-created_at')[:5]
# 2. 내가 쓴 댓글 (최신순 5개)
# select_related('post'): 댓글이 달린 게시글 제목도 같이 가져오기 위해 (DB 성능 최적화)
my_comments = Comment.objects.filter(author=request.user).select_related('post').order_by('-created_at')[:5]
# 3. 내가 좋아요 한 글 (최신순 5개)
# STEP 4에서 related_name='like_posts'로 설정했었습니다.
like_posts = request.user.like_posts.all().order_by('-id')[:5]
# --- [섹션 2] 커뮤니티 현황 ---
# 4. 통합 인기글 (조회수 높은 순 Top 5)
hot_posts = Post.objects.all().order_by('-views')[:5]
# 5. 자유게시판(free) 최신글 Top 5
# (주의: 관리자 페이지에서 코드가 'free'인 게시판을 먼저 생성해야 데이터가 나옵니다)
free_posts = Post.objects.filter(board__code='free').order_by('-created_at')[:5]
context = {
'my_posts': my_posts,
'my_comments': my_comments,
'like_posts': like_posts,
'hot_posts': hot_posts,
'free_posts': free_posts,
}
return render(request, 'home.html', context)
4. 화면 만들기 (templates/home.html)
templates 폴더(최상위)에 home.html 파일을 새로 만듭니다.
Bootstrap의 Grid System을 사용하여 상단에는 내 활동(3단), 하단에는 커뮤니티 현황(2단)을 배치합니다.
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="col-12 mb-4">
<div class="p-4 bg-light rounded-3 border">
<h3>👋 안녕하세요, {{ user.username }}님!</h3>
<p class="text-muted mb-0">오늘도 즐거운 커뮤니티 활동 되세요.</p>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100 shadow-sm">
<div class="card-header bg-white">
<i class="bi bi-pencil-square text-primary"></i> <strong>내가 쓴 글</strong>
</div>
<ul class="list-group list-group-flush">
{% for post in my_posts %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="{% url 'boards:board_detail' post.board.code post.pk %}" class="text-decoration-none text-dark text-truncate" style="max-width: 70%;">
{{ post.title }}
</a>
<span class="badge bg-light text-secondary rounded-pill">{{ post.views }} view</span>
</li>
{% empty %}
<li class="list-group-item text-center text-muted small py-3">작성한 글이 없습니다.</li>
{% endfor %}
</ul>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100 shadow-sm">
<div class="card-header bg-white">
<i class="bi bi-chat-dots text-success"></i> <strong>내가 쓴 댓글</strong>
</div>
<ul class="list-group list-group-flush">
{% for comment in my_comments %}
<li class="list-group-item">
<div class="text-truncate small mb-1">
<a href="{% url 'boards:board_detail' comment.post.board.code comment.post.pk %}" class="text-decoration-none text-dark">
{{ comment.content }}
</a>
</div>
<div class="text-muted" style="font-size: 0.75rem;">
<i class="bi bi-arrow-return-right"></i> {{ comment.post.title|truncatechars:15 }}
</div>
</li>
{% empty %}
<li class="list-group-item text-center text-muted small py-3">작성한 댓글이 없습니다.</li>
{% endfor %}
</ul>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100 shadow-sm">
<div class="card-header bg-white">
<i class="bi bi-heart-fill text-danger"></i> <strong>좋아요 한 글</strong>
</div>
<ul class="list-group list-group-flush">
{% for post in like_posts %}
<li class="list-group-item">
<a href="{% url 'boards:board_detail' post.board.code post.pk %}" class="text-decoration-none text-dark d-block text-truncate">
{{ post.title }}
</a>
<div class="small text-muted text-end mt-1">
by {{ post.author.username }}
</div>
</li>
{% empty %}
<li class="list-group-item text-center text-muted small py-3">좋아요 한 글이 없습니다.</li>
{% endfor %}
</ul>
</div>
</div>
</div>
<div class="row mt-2">
<div class="col-12 my-3">
<hr>
<h5 class="text-secondary"><i class="bi bi-activity"></i> 커뮤니티 현황</h5>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100 border-danger border-opacity-25">
<div class="card-header bg-danger bg-opacity-10 text-danger">
<i class="bi bi-fire"></i> <strong>지금 뜨는 인기글</strong>
</div>
<ul class="list-group list-group-flush">
{% for post in hot_posts %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center text-truncate" style="max-width: 80%;">
<span class="badge bg-secondary me-2" style="font-size: 0.7rem;">{{ post.board.name }}</span>
<a href="{% url 'boards:board_detail' post.board.code post.pk %}" class="text-decoration-none text-dark text-truncate">
{{ post.title }}
</a>
{% if post.comments.count > 0 %}
<span class="text-danger small ms-1">[{{ post.comments.count }}]</span>
{% endif %}
</div>
<span class="badge bg-danger rounded-pill">{{ post.views }}</span>
</li>
{% empty %}
<li class="list-group-item text-center text-muted small py-3">아직 인기글이 없습니다.</li>
{% endfor %}
</ul>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-light">
<i class="bi bi-clock"></i> <strong>자유게시판 최신글</strong>
</div>
<ul class="list-group list-group-flush">
{% for post in free_posts %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="{% url 'boards:board_detail' post.board.code post.pk %}" class="text-decoration-none text-dark text-truncate" style="max-width: 75%;">
{{ post.title }}
</a>
<div class="small text-muted">
{{ post.author.username }}
</div>
</li>
{% empty %}
<li class="list-group-item text-center text-muted small py-3">게시글이 없습니다.</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}
5. 네비게이션 바 수정 (templates/base.html)
마지막으로 상단 메뉴바의 로고나 Home 버튼을 눌렀을 때, 방금 만든 대시보드로 이동하도록 링크를 수정합니다.
templates/base.html의 네비게이션 부분을 찾아 수정하세요.
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container">
<a class="navbar-brand" href="{% url 'home' %}">My Board</a>
6. 테스트
- 로그인 확인 : 로그아웃 상태라면 로그인 페이지로 이동하는지 확인합니다.
- 메인 접속: ' http://127.0.0.1:8000/' 으로 접속합니다.
- 데이터 확인:
- 상단에 **내 활동(글/댓글/좋아요)**이 잘 나오나요?
- 하단에 **인기글(조회수 순)**과 **자유게시판 최신글**이 잘 나오나요?
- 클릭 테스: 각 항목을 클릭했을 때 해당 게시글로 잘 이동하는지 확인합니다.
'Step by Step > [phase 2] django community upgrade' 카테고리의 다른 글
| 7. 사용자 간 1:1 쪽지 기능(DM) 구현 (0) | 2025.12.07 |
|---|---|
| 6. 회원 프로필(닉네임 & 아바타) (0) | 2025.12.07 |
| 4. 좋아요(추천) 기능 (M:N 관계) 구현 (0) | 2025.12.02 |
| 3. 이미지 및 파일 첨부 기능 구현 (0) | 2025.12.02 |
| 2. 댓글 수정 및 삭제 (0) | 2025.12.01 |