5. 메인 페이지(대시보드 & 데이터 조회) 구현

이번 단계에서는 웹사이트의 대문인 메인 페이지를 만듭니다.

로그인한 사용자가 접속했을 때 "내가 쓴 글", "내 댓글", "좋아요 한 글"을 한눈에 볼 수 있는 대시보드(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. 테스트

  1. 로그인 확인 : 로그아웃 상태라면 로그인 페이지로 이동하는지 확인합니다.
  2. 메인 접속: ' http://127.0.0.1:8000/' 으로 접속합니다.
  3. 데이터 확인:
    • 상단에 **내 활동(글/댓글/좋아요)**이 잘 나오나요?
    • 하단에 **인기글(조회수 순)**과 **자유게시판 최신글**이 잘 나오나요?
  4. 클릭 테스: 각 항목을 클릭했을 때 해당 게시글로 잘 이동하는지 확인합니다.