Contents
django 8 - 게시판 코드 수정(최적화)
   2022년06월20일     7분정도면 다 읽어요     - Comments

[카카오 클라우드 스쿨] django 8 - 게시판 코드 수정(최적화)

게시판 코드 수정(최적화)

실사용 코드에 가깝게 만들기
기능 추가하기

8-1. django 의 forms.py 사용

1 . 입력 폼에 < > { % - # ‘ 등등 입력하면 보안상으로 위험하기 때문에 원래같으면 등록을 다 했어야 함

2 . 그러나 요새는 간단하게 몇 줄 가지고 해결 가능하다

3 . boardpan 앱 하단에 forms.py 파일 하나 생성한다

  • HTML의 기본 폼 양식(작동양상)을 설정할 수 있다

forms.py

from django import forms
from boardpan.models import Post
# 모델의 클래스를 import 한다

class PostForm(forms.ModelForm):
    # 어떤 모델 형식인지 써 줘야함 (이 모델의 양식을 쓸 것이다)
    class Meta:
        model = Post  # model의 클래스명(Post 형태의 class이다)
        fields = ('title', 'contents')  # 어떤 필드들을 입력 받을 지 명시 (시간은 따로 입력받지 않으니 안 써도 됨)
        # exclude = ('userid',)  # 입력받고 싶지 않은 것을 명시 (아직은 없음)

views.py 수정

from boardpan.forms import PostForm
def createGet(request):
    postForm = PostForm()
    context = {'postForm': postForm}  # 항상 컨텍스트는 dict 형태
    return render(request, 'boardpan/create.html', context)

# createPost에서 form에서 쓴 이름과 같이 ptitle -> title로 변경
def createPost(request):
    # 객체 생성!
    post = Post()
    post.title = request.POST.get('title', None)
    post.contents = request.POST.get('contents', None)

    # DB에 저장!
    post.save()

4 . 템플릿 수정

  • form 양식을 django의 forms에 작성했기 때문에 html 내부에서 작성할 필요가 없어짐

html(기존)

<form action="createPost" method="post">
    { % csrf_token % }
    <input type="text" name="ptitle" />
    <input type="text" name="pcontents" />
    <button>저장</button>
</form>

html(이후) - postform을 통해 간소화 됨

<form action="createPost" method="post">
    { % csrf_token % }
    { { PostForm } }
    <button>저장</button>
</form>
  • 위의 변수 { { PostForm } } 는 views에서 context로 전달한 변수명과 동일해야 함

5 . 접속을 해 보면 모양이 조금 변경되었지만 작동은 잘 함

  • img_66
  • charfield 는 그냥 일반적인 인풋 양식처럼 보이고
  • textfield 는 여러줄을 쓸 수 있게 수정이 됨
    • 페이지 소스를 보면 maxlength 속성이 알아서 추가 됨, 레이블도 표시됨



8-2. forms 활용한 코드 수정

실제로는 여러 필드를 받아갈 경우, 입력을 안한 내용에 대해 검증이 가능하게 되며
하나씩 입력받지 않더라도 더욱 간소하게 입력을 받아갈 수 있다

views.py (변경 전)

# 디비에 저장할 POST
def createPost(request):
    # 객체 생성!
    post = Post()
    post.title = request.POST.get('title', None)
    post.contents = request.POST.get('contents', None)

    # DB에 저장!
    post.save()

    # 작성되었습니다 페이지로 이동함
    return render(request, 'boardpan/createResult.html')

views.py (변경 후)

# 디비에 저장할 POST
def createPost(request):
    # 폼한테 전달해주면 알아서 title 및 contents를 넣어 준다
    postForm = PostForm(request.POST)

    # 폼이 유효한지 확인하고, 유효하다면 저장한다
    if postForm.is_valid():
        post = postForm.save(commit=False)
        # false: 굳이 저장을 안 시키고, 모델의 객체를 반환한다
        # 예전에는 저장해서 중복, 에러 등을 확인하는 데에 쓰였는데, 요즘에는 필요 없음
        post.save()
        return render(request, 'boardpan/createResult.html')

    # 아니면 저장하지 않는다
    else:
        # return redirect('/board/readGet/'+str(post.id))
        return HttpResponse('오류 발생함.')



8-3. POST와 GET 합치기 (URL 및 VIEW)

url.py

# 두 개 였던 URL을 하나로 합침
    # path('boardpan/createGet', boardpan.views.createGet),
    # path('boardpan/createPost', boardpan.views.createPost),
    path('boardpan/create', board.views.create)

views.py

  • post와 get을 합칠 수 있음(if문)
  • def createPost(request) 및 def createGet(request) 을 지우고 다음을 생성하면 됨
# 하나로 합친 POST/GET
def create(request):
    # request가 GET 방식이면 수행하는 코드(입력 페이지를 클라이언트에 전달해 줌)
    if request.method == "GET":
        postForm = PostForm()
        context = {'postForm': postForm}
        return render (request, 'boardpan/create.html', context)

    # request가 POST 방식이면 수행하는 코드(입력 양식을 받아감)
    elif request.method == "POST":
        # 값을 Form에 전달
        postForm = PostForm(request.POST)

        # 폼에 전달받은 값 검증
        if postForm.is_valid():
            post = postForm.save(commit=False)
            post.save()
            return render(request, 'boardpan/createResult.html')
  • 경로가 바뀌었으니 html도 바꿔야 함
        <form action="create" method="post">

백엔드만 간소하게 바뀌었지 사용자가 이용하는 것은 그대로임



8-4. 최신 게시글일수록 위로 오도록 정렬

최신 게시글일수록 위로 오도록 수정해 보자

views.py

def listGet(request):
    # order by로 정렬이 가능함, id로 정렬하되 오름차순 (-)
    posts = Post.objects.all().order_by('-id')
  • 첫번째 줄에서 id를 기준으로 오름차순으로 정렬하게 만들어 봄



8-5. 게시글 조회하는 페이지에서 게시글로 링크생성

list(목록)에서 클릭시 게시글(read)를 조회하는 페이지로 이동할 수 있도록 하자

1 . 우선 html 템플릿에 링크를 하나 만들었음
list.html (전체 목록 보는 사이트)


<body>

    { % for post in posts % }
    <div> { {post.id} } &nbsp; &nbsp; &nbsp; &nbsp; |
    <a href="readGet/{ {post.id} }"> { {post.title} } </a>
    </div>
    <hr />
    { % endfor % }

    { % for post in posts % }
        { { post.id } }
        # { { post.contents } }
        # { { post.title } }

        <a href="readGet?id={ {post.id} }"> { {post.title} }</a> <br/>  # 옛날 방식
        { {post.id} }  # 요즘 방식
        <a href="readGet/{ {post.id} }"> { {post.title} }</a> <br />  # 요즘 방식

    { % endfor % }
</body>

2 . 요즘 방식을 쓸 경우 URL을 다음과 같이 readGet을 바꿔 줘야야 함

# 변수가 되어야 함, 보드의 id라는 뜻으로 bid 라고 변수 지정 (int)
... path('board/readGet/<int:bid>', board.views.readGet),

bid:URL에서 변수를 쓸 수 있음, 1번글 1번 페이지, 2번글 2번 페이지…
URL에 변수를 지정해 여러 페이지에 접근 가능하게 함
ex) readGet/2 -> 게시물 중 2번 id를 가진 친구를 조회하기 됨

3 . 또한 views에서 변수도 같이 넣어 줘야 함
고치기 전 view

# 게시글 하나를 조회한다
def readGet(request):
    # 객체를 생성해서 변수로 담는다
    id = request.GET.get('id', None)
    post = Post.objects.filter(id=1)
    print(post)
    context = {'posts': post}

    # context값과 함께 클라이언트에 리턴
    return render(request, 'boardpan/read.html', context)

수정한 view

# 게시글 하나를 조회한다, 파라미터로 bid값도 같이 줌
def readGet(request, bid):
    post = Post.objects.filter(id=bid)
    print(post)
    context = {'posts': post}

    # context값과 함께 클라이언트에 리턴
    return render(request, 'boardpan/read.html', context)

4 . 게시물 조회하는 방식 바꾸기 (read)

  • 조회 시 filter를 쓰면 리스트의 하나로 들어가게 됨’
  • 다음과 같이 get방식을 사용하는 방법도 있다
from django.db.models import Q
def readGet(request, bid):
    post = Post.objects.get(Q(id=bid))
    print(post)
    context = {'post': post}

    # context값과 함께 클라이언트에 리턴
    return render(request, 'boardpan/read.html', context)

5 . 그래서 read.html에서도 반복문의 제거가 가능하게 됨.

read.html

<body>
    { % if post % }
        글번호: { { post.id } } <br/>
        제목: { { post.title } } <hr/>
        { { post.contents } }
    { % endif % }
</body>
  • 참고로 위 post는 views에서 ‘post’ 와 이름이 동일해야 한다

6 . 결과

  • img_67
  • (타이틀 클릭시)
    img_68


참고: jekyll 블로그 특성항 템플릿 언어 { {, { % 등등이 적용이 안되어 불가피하게 공백을 삽입했어요
원래는 공백 있으면 안돼요