Django

210201_01_Django_(3)_게시판 웹 어플리케이션 예제

SW Kang 2021. 2. 1. 09:03

1. Model 개발

    1) 테이블 정의 : models.py

    2) Admin 사이트에 테이블 반영 : admins.py

    3) 데이터베이스 변경 사항 반영 : manage.py makemigrations

                                                      manage.py migrate

 

1) 게시판 테이블 정의

> 필요한 테이블 정의 : User 테이블과 Board 테이블 생성 

models.py

from django.db import models
from django.db.models.deletion import CASCADE, SET_DEFAULT, SET_NULL
				//Cascade : 부모 레코드 삭제 시 자식 레코드도 함께 삭제
				//Set_Default : 부모 레코드 삭제 시 외래 키를 Default 값으로 변경
				//Set_Null : 부모 레코드 삭제 시 외래 키를 Null 값으로 변경

# Create your models here.
class User(models.Model):
    user_name = models.CharField(max_length=200, null=False)
    user_id = models.CharField(max_length=200, null=False, primary_key=True)
    user_password = models.CharField(max_length=200, null=False)
    def __str__(self):
        return self.user_name
    
class Board(models.Model):
    title = models.CharField(max_length=100)
    content = models.CharField(max_length=500)
    writer_id = models.ForeignKey(User, on_delete=SET_DEFAULT, default="")
		// on_delete=SET_DEFAULT, default="" : 유저 삭제 시 게시물의 유저 ID가 Default값인 ""로 변경
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return self.content

 

2) Admin 페이지에 테이블 반영

admins.py

from django.contrib import admin
from board.models import Board, User

# Register your models here.
admin.site.register(Board)
admin.site.register(User)

 

3) 데이터베이스에 변경 사항 적용

> python manage.py makemigrations

   python manage.py migrate

 

 

2. View와 Template 개발

    1) url 등록

    2) view : 작동할 함수 정의

    3) template : HTML 문서 작성

 

1) URL 과 View 이름 매핑

myDjangoSite2/urls.py

from django.conf.urls import url
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
	url(r'^admin/', admin.site.urls),
	path('board/', include('board.urls')),
    	// board/ 뒤에 오는 url 주소 > board.url에 등록
]

 

myDjangoSite2/board/urls.py

from django.urls import path
from board import views

app_name = 'board'

urlpatterns = [
	// board/ 뒤에 오는 url 주소 정의
       
	path('login/', views.login, name='login'),
    	// login.html Template : 로그인 화면
	path('loginProcess/', views.loginProcess, name='loginProcess'),
    	// 로그인 성공 시 /boardList/redirect
	path('', views.boardList, name='board'),
    	// boardList.html : 게시판 글 목록
	path('boardList/<int:curr_page>', views.boardList, name='boardList'),
    	// boardList.html : 게시판 글 목록
	path('boardDetail/<int:board_id>', views.boardDetail, name='boardDetail'),
    	// boardDetail.html : 게시판 글 상세보기
]

 

2) View index() 및 template 작성

a. views.py : view index() 작성

from django.shortcuts import render

# Create your views here.
def login(request):
    return render(request, "boardList.html")

def loginProcess(request):
    return render(request, "boardList.html")

def boardList(request, curr_page = 1):
    return render(request, "boardList.html")

def boardDetail(request, board_id = 1):
    return render(request, "boardList.html")

 

b. template/boardList.html : template 작성


폼(Form) 클래스와 세션(Session), 리다이렉트(Redirect)

 

(Form) 클래스

> html 문성 작성시 태그를 자동으로 생성해주는 클래스

> 폼 클래스를 미리 객체를 만들어 놓은 후에 view와 html 에서 사용하면 자동으로 파라미터를 가져다가 사용한다.

1) forms.py 에 클래스 정의
2) 폼을 렌더링할 템플릿 변경
3) 뷰에서 폼 클래스 인스턴스 생성 및 객체 리턴

폼 클래스의 장점

    1. form 생성에 필요한 데이터를 폼 클래스로 구조화

    2. 폼 클래스의 데이터로 렌더링하여 HTML form 생성

    3. 사용자로부터 제출된 form 과 data 수신과 처리

 

세션 (Session)

> 논리적인 연결

> 네트워크 망에서 사용자 간의 또는 컴퓨터 간의 통신을 위한 논리적인 연결 상태

> 논리적인 연결 상태를 유지하기 위하여 세션id 를 부여

> 세션id가 유지되는 동안 논리적인 연결 유지

 

세션 ID 의 예시

> 네이버에 로그인하면 WAS 에서 사용자에게 세션 ID 부여

> 브라우저를 닫기 전까지 세션 ID 유지

> 세션 ID 가 유지되는 동안 로그인한 권한 유지

> 브라우저 닫는 순간 세션 ID 삭제

> 다시 브라우저를 열면 로그인했던 세션ID 가 없기 때문에 로그아웃된 상태

 

  • 세션에서 값을 얻을 시
data = request.session.get("세션 이름")

 

  • 세션에서 값을 저장 시 : 로그인 성공시 세션에 사용자 이름 등록
request.session['세션 이름'] = 값

//request.session['loginuser'] = user.user_name

 

 

리다이렉트 (Redirect)

> 방향재지정

> 웹 서버에 URL 요청이 들어왔을 때, 서버에서 다른 URL로 요청을 돌려서 브라우저의 방향을 재지정해 주는 것

> 리다이렉션이 발생할 시 요청한 URL이 아닌 다른 URL 주소로 바뀐다

 


 

1. 로그인 기능

1) 로그인 폼 클래스 생성

forms.py

class LoginForm(forms.Form):
    login_id = forms.CharField(label = "아이디", max_length=100, required=True)
    login_pw = forms.CharField(label = "패스워드", max_length=100, required=True, widget=forms.PasswordInput)

2) 로그인 페이지 생성

templates/login.html

<form action = "{% url 'board:loginProcess' %}" method="post">
		// submit 버튼을 눌렀을 때 action > url : board.loginProcess 요청

        {% csrf_token %}
        <table>
            {{ form }}
        </table>
        <input type = "submit" value="Login"/>
    </form>

3) login 함수 수정

views.py : login()

def login(request):
    form = LoginForm()
    return render(request, "login.html", {'form':form})

 

2. 로그인 처리 기능

1) loginProcess 함수 수정

views.py : loginProcess()

def loginProcess(request):
    form = LoginForm(request.POST)
    errormessage = ""

    if form.is_valid():
        login_id = form.cleaned_data["login_id"]
        login_pw = form.cleaned_data["login_pw"]
        print(login_id, login_pw)

        try:
            user = User.objects.get(pk=login_id, user_password=login_pw)
            print(user)
            if user:
                request.session["loginuser"] = user.user_name
                return HttpResponseRedirect("/board/boardList/1")
                // 로그인 성공 시 리다이렉트 boardList/1 로 이동
            else:
                errormessage = "1 Login Failed. User ID and PW do not Match"
                context = {"errormessage":errormessage}
                return render(request, "login.html", context)
        except(User.DoesNotExist):
            errormessage = "2 Login Failed. User does not Exist"
            context = {"errormessage":errormessage}
            return render(request, "login.html", context)
    return render(request, "boardList.html")

로그아웃을 하고 싶다면 Session_id 를 invalid 시키는 함수를 사용한다.

 

2) 에러 메세지 추가

templates/login.html

<body>
    {% if errormessage %}		// 에러메세지가 존재할 시
        {{ errormessage }}		// 에러메세지 출력
    {% endif %}				// 조건문 종료

    <form action = "{% url 'board:loginProcess' %}" method="post">
        {% csrf_token %}
        <table>
            {{ form }}
        </table>
        <input type = "submit" value="Login"/>
    </form>

</body>

3. 게시판 목록보기 기능

1) boardList 함수 수정

views.py : boardList()

def boardList(request, curr_page = 1):
    if not request.session.get("loginuser"):
        return HttpResponseRedirect("/board/login")

    cntPerPage = 10
    endCnt = curr_page * cntPerPage
    startCnt = endCnt - cntPerPage
    print(startCnt, endCnt)

    totalCnt = Board.objects.count()
    tpn = int(totalCnt/cntPerPage+1)
    totalPageCnt = []
    for i in range(1, tpn+1):
        totalPageCnt.append(i)

    board_list = Board.objects.all().order_by('-id')[startCnt:endCnt]
    context = {"board_list":board_list, "totalPageCnt":totalPageCnt, "curr_Page":curr_page}
    return render(request, "boardList.html",context)

 

2) 게시판 페이지 생성

templates/boardList.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>게시판 목록</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
</head>
<body>
    <div class="container">
        <h1> 게시판 글목록 </h1>
        <p>{{ request.session.loginuser }} 님 안녕하세요.</p>
        <p></p>

        <table class="table table-hover">
            <tr>
                <th>글번호</th><th>제목</th><th>작성자</th><th>등록일</th>
            </tr>
            {% if board_list %}
                {% for board in board_list %}
                <tr>
                    <td>{{board.id}}</td>
                    <td><a href = "{% url 'board:boardDetail' board.id %}">{{board.title}}</a></td>
                    // boardDetail 요청 > 요청할 때, board.id 를 가져와서 boardDetail/board.id로 넘겨줌
                    <td>{{board.writer_id}}</td>
                    <td>{{board.pub_date}}</td>
                </tr>
                {% endfor %}
            {% endif %}
        </table>

        <table>
            <tr>
                <td>페이지 번호 &nbsp; &nbsp;</td>
                <td>
                    {% for p in totalPageCnt %}
                        {% if curr_page != p %}<a href="{% url 'board:boardList' p %}" >{{p}} </a>
                        {% else  %} {{ p }}
                        {% endif %}
                    {% endfor %}
                </td>
            </tr>
        </table>
    </div>
</body>
</html>

 

4. 게시판 글 상세보기 기능

1) boardDetail 함수 수정

views.py

def boardDetail(request, board_id = 1):
    if not request.session.get("loginuser"):
        return HttpResponseRedirect("/board/login")
    board = Board.objects.get(pk=board_id)
    context = {"board":board}
    return render(request, "boardDetail.html", context)

 

2) 게시판 상세보기 페이지 생성

templates/boardDetail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>게시판글 상세 보기 </title>
</head>

<body>
    <div class="container">
        <h1>
            {{ board.title }}
        </h1>
        <p>
            {{ board.content }}
        </p>
    </div>
    <p> 작성자 : {{ board.writer_id }}</p>
    <p> <a href="{% url 'board:board'  %}" > 글목록 보기 </a> </p>
</body>
</html>