[카카오 클라우드 스쿨] 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 . 접속을 해 보면 모양이 조금 변경되었지만 작동은 잘 함
- 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} } |
<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 . 결과
- (타이틀 클릭시)
참고: jekyll 블로그 특성항 템플릿 언어 { {, { % 등등이 적용이 안되어 불가피하게 공백을 삽입했어요
원래는 공백 있으면 안돼요