본문 바로가기

Django

20210205_Django 예외 처리, 기능보완, request.get, request.GET, 페이징(paginator, page)

Django 게시판


게시판 예외처리

  • 예외 처리 함수
    • try : 에러나 날수도 있는 함수 부분
    • except : 에러가 나는 경우 실행 코드
      • except 모델.에러명:을 통해서 특정 에러에 대해 조건을 줄수 있다. 에러명은 django에서 사이트 돌릴때 해당 사이트의 에러창을 참고


  • 예외 상황
    • 존재하지 않는 아이디로 로그인 하는 경우
    • 없는 글의 pk로 글 자세히 보기를 하는 경우
    • 로그인 없이 글을 쓰는 경우

페이징 기능

  • 게시글이 어느 정도 이상 생기는 경우 페이지를 생성해서 넘길수 있게 하는 기능

html 만들기

  • 목록 하단에 네비게이터를 이용하여 페이징 버튼 만들기
{% raw %}
{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12">
        <table class="table table-light">
            <thead class="thead-light">
                <tr>
                    <th>#</th>
                    <th>제목</th>
                    <th>아이디</th>
                    <th>일시</th>
                </tr>
            </thead>
            <tbody class="text-dark">
                {% for board in boards %}
                <tr>
                    <th>{{ board.id }}</th>
                    <td>{{ board.title }}</td>
                    <td>{{ board.writer }}</td>
                    <td>{{ board.registered_dttm }}</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
</div>
<div class="row mt-2">
    <div class="col-12">
        <nav>
            <ul class="pagination justify-content-center">
                <li class="page-item">
                    <a href="#" class="page-link">이전으로</a>
                </li>
                <li class="page-item active">
                    <a href="#" class="page-link">1/1</a>
                </li>
                <li class="page-item">
                    <a href="#" class="page-link">다음으로</a>
                </li>
            </ul>
        </nav>
    </div>
</div>
<div class="row">
    <div class="col-12">
        <buttton class="btn btn-primary">글쓰기</buttton>
    </div>
</div>
{% endblock %}
{% endraw %}


view 만들기

  • request.get vs request.GET.get
  • dict형 변수.get() : python 메소드로 사전형 데이터를 가져와 안에 key값을 넣으면 해당하는 value를 할당 특징은 값이 없으면 none 값을 반환해서 에러가 나지 않음 (key, value) 파라미터의 경우 value는 key가 존재하지 않는 경우의 default value 값을 지정하는 것 따로 지정안하면 none
  • request.GET : Django에서 사용하는 request를 GET을 통해서 사전형으로 바꾸어 주기 때문에 []을 통해서 url 파라미터를 가져 올수 있음
  • request.GET.get : Django 와 python의 합작으로 request를 사전으로 가져오면서 값이 없을때 에러를 반환하지 않는다.

  • Paginator , Page
  • class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True) : 한 페이지 안에 몇개의 object를 넣을 것인지 설정하여 page 객체로 만들어 버림
    • 파라미터
    • object_list : 채울 QuerySet 즉, 오브젝트들이 모여있는 모델 객체
    • per_page : 한 페이지에 보이게 할 오브젝트의 개수
    • orphans : 마지막 페이지의 남는 숫자의 오브젝트를 이전의 페이지에 넣을 개수
    • allow_empty_first_page : True이면 첫번째 페이지를 빈 페이지를 허용(에러 없음) False면 error 발생

  • .get_page() : page객체의 해당 페이지를 리턴 함, 괄호안에 number 넣어서 리턴할 페이지 설정
from django.shortcuts import render, redirect
from sl_user.models import Sl_user
from .models import Board
from .forms import BoardForm
from django.http import Http404
from django.core.paginator import Paginator
# Create your views here.


def board_list(request):
    # all()은 모든 오브젝트를 가져오고 order_by는 정렬인데 '-'는 역순을 의미 즉, 최신것으로 가져오겠다.
    all_boards = Board.objects.all().order_by('-id')
    page = int(request.GET.get('p', 1)) 
    paginator = Paginator(all_boards, 2)  # Paginator 화면에 보여줄 게시글 수를 설정하여 page 객체로 만들어 버림

    boards = paginator.get_page(page)

    return render(request, 'board_list.html', {'boards': boards})


html 수정하기(view에 맞게 포맷팅, 예외처리)

  • html에 가서 request 받을 값 설정(page class의 method를 활용하여 포맷팅) 하여 view에서 request 받아 실행 할수 있게 함
  • 중간 현재 페이지 넘버 포맷팅
  • 예외 처리) 이전 번호가 없는 경우, 이후 번호가 없는 경우
  • 더이상 이전 이후가 없을 경우 li 요소의 disabled 활성화
{% raw %}
{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12">
        <table class="table table-light">
            <thead class="thead-light">
                <tr>
                    <th>#</th>
                    <th>제목</th>
                    <th>아이디</th>
                    <th>일시</th>
                </tr>
            </thead>
            <tbody class="text-dark">
                {% for board in boards %}
                <tr>
                    <th>{{ board.id }}</th>
                    <td>{{ board.title }}</td>
                    <td>{{ board.writer }}</td>
                    <td>{{ board.registered_dttm }}</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
</div>
<div class="row mt-2">
    <div class="col-12">
        <nav>
            <ul class="pagination justify-content-center">
                    {% if boards.has_previous %}
                <li class="page-item">
                    <a href="?p={{ boards.previous_page_number }}" class="page-link">이전으로</a>
                </li>
                    {% else %}
                <li class="page-item disabled">
                    <a href="#" class="page-link">이전으로</a>
                </li>
                    {% endif %}
                <li class="page-item active">
                    <a href="#" class="page-link">{{ boards.number }}/{{ boards.paginator.num_pages}}</a>
                </li>
                   {% if boards.has_next %}
                <li class="page-item">
                    <a href="?p={{ boards.next_page_number }}" class="page-link">다음으로</a>
                </li>
                    {% else %}
                <li class="page-item disabled">
                    <a href="#" class="page-link">다음으로</a>
                </li>
                    {% endif %}
            </ul>
        </nav>
    </div>
</div>
<div class="row">
    <div class="col-12">
        <buttton class="btn btn-primary">글쓰기</buttton>
    </div>
</div>
{% endblock %}
{% endraw %}


Django 게시판 기능 보완

홈 화면

  • 로그인 버튼 (로그인 상태에서는 로그 아웃 버튼)

  • 회원가입 버튼

  • 게시물 보기 버튼

  • 내가 구현하고자 했던 기능

    • 로그인 하면 로그인된 아이디 표시 기능(@@님 환영합니다.), 로그아웃시에는 (로그인이 필요합니다.)
      • render 에서 엄청 애를 먹었는데 이유는 render의 context가 항상 어떤 값으로 지정이 되어야 에러가 없다. 만약 변수가 지정 안되있으면 bound 에러가 발생하는 듯하다.
{% raw %}
{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12 text-center">
        <h1>홈페이지</h1>
    </div>
</div>
<div class="row mt-5">
    <div class="col-12 text-center">
        {% if request.session.user %}
        <h3>{{ k }}님 환영합니다.</h3>
        {% else %}
        <h3>{{ k }}</h3>
        {% endif %}
    </div>
</div>
<div class="row mt-4">
    {% if request.session.user %}
    <div class="col-12">
        <button class="btn btn-primary btn-block" onclick="location.href='/fcuser/logout/'">로그아웃</button>
    </div>
        {% else %}
    <div class="col-6">
        <button class="btn btn-primary btn-block" onclick="location.href='/fcuser/login/'">로그인</button>
    </div>
    <div class="col-6">
        <button class="btn btn-primary btn-block" onclick="location.href='/fcuser/register/'">회원가입</button>
    </div>
        {% endif %}
</div>
<div class="row mt-4">
    <div class="col-12">
        <button class="btn btn-primary btn-block" onclick="location.href='/board/list/'">게시물</button>
    </div>
</div>
{% endblock %}
{% endraw %}

  • view 수정
def home(request):
    user_id = request.session.get('user')

    if user_id:
        sl_user = Sl_user.objects.get(pk=user_id)  # pk primary key
        k = fcuser
    else:
        k = "로그인이 필요합니다."
    return render(request, 'home.html', {'k': k})
  • 어차피 k 모델의 경우 객체가 기본 self.username 으로 되어 있기 때문에 k를 바로 사용해도 괜찮았다.


게시물 화면

  • 홈 돌아가기 버튼 추가 및 연결
  • 글쓰기 버튼 연결
{% raw %}
{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12">
        <table class="table table-light">
            <thead class="thead-light">
                <tr>
                    <th>#</th>
                    <th>제목</th>
                    <th>아이디</th>
                    <th>일시</th>
                </tr>
            </thead>
            <tbody class="text-dark">
                {% for board in boards %}
                <tr>
                    <th>{{ board.id }}</th>
                    <td>{{ board.title }}</td>
                    <td>{{ board.writer }}</td>
                    <td>{{ board.registered_dttm }}</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
</div>
<div class="row mt-2">
    <div class="col-12">
        <nav>
            <ul class="pagination justify-content-center">
                {% if boards.has_previous %}
            <li class="page-item">
                <a href="?p={{ boards.previous_page_number }}" class="page-link">이전으로</a>
            </li>
                {% else %}
            <li class="page-item disabled">
                <a href="#" class="page-link">이전으로</a>
            </li>
                {% endif %}
            <li class="page-item active">
                <a href="#" class="page-link">{{ boards.number }}/{{ boards.paginator.num_pages}}</a>
            </li>
               {% if boards.has_next %}
            <li class="page-item">
                <a href="?p={{ boards.next_page_number }}" class="page-link">다음으로</a>
            </li>
                {% else %}
            <li class="page-item disabled">
                <a href="#" class="page-link">다음으로</a>
            </li>
                {% endif %}
        </ul>
        </nav>
    </div>
</div>
<div class="row mt-1">
    <div class="col-2">
        <buttton class="btn btn-primary btn-block" onclick="location.href='/board/write/'">글쓰기</buttton>
    </div>
    <div class="col-2">
        <buttton class="btn btn-primary btn-block" onclick="location.href='/'">홈</buttton>
    </div>
</div>

{% endblock %}
{% endraw %}



글쓰기 화면

  • 목록 돌아가기 버튼 추가 및 연결
{% raw %}
{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12">
        <form method="POST", action=".">
            {% csrf_token %}
            {% for field in form %}
            <div class="form-group">
                <label for="{{ field.id_for_label }}">{{ field.label }} </label>
                <!-- {{ field.field.widget.name}} -->
                {% ifequal field.name 'contents' %}
                <textarea class="form-control" name="{{ field.name }}" placeholder="{{ field.label }}"></textarea>
                {% else %}
                <input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}" placeholder="{{ field.label }}" name="{{ field.name }}">
                {% endifequal %}
            </div>
            {% if field.errors %}
            <span style="color: red">{{ field.errors }}</span>
            {% endif %}
            {% endfor %}
            <button type="submit" class="btn btn-primary">글쓰기</button>
            <div class="col-3">
            <buttton class="btn btn-primary btn-block" onclick="location.href='/board/list/'">목록</buttton>
            </div>
        </form>
    </div>
</div>
{% endblock %}
{% endraw %}

글 보기 화면

  • 목록 돌아가기 버튼 추가 및 연결
{% raw %}
{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12">
        <div class="form-group">
            <label for="title">제목</label>
            <input type="text" class="form-control" id="title" value="{{ board.title }}" readonly>
            <label for="contents">내용</label>
            <textarea class="form-control" readonly>{{ board.contents }}</textarea>
        </div>
        <button class="btn btn-primary" onclick="location.href='/board/list/'">목록</button>
    </div>
</div>
{% endblock %}
{% endraw %}