https://github.com/YoonKeumJae/LikeLion/tree/main/BE/HomeWork/week3
멋사 BE Django수업의 첫날은 models.py 작성이었습니다. models.py는 어렵지 않게 작성하였지만, 다음 과제인 views.py를 작성하면서 꽤 애먹었어요. 이번 과제의 목표는 views.py에서 post에 대한 CRUD기능을 만들고 tests.py에서 테스트 코드를 작성하는 것이었습니다. 예제 코드가 있었지만 봐도 무슨 말인지 모르겠고, 운영진분이 추천하는 책도 사서 조금 읽었지만 이해가 될 듯 말 듯하고.. chatGPT한테 예제 코드를 물어봐가면서 어떻게든 해내버렸습니다.
views.py는 MVT패턴의 View를 담당하는 파일입니다. MVT패턴이란 Model이 data를, View가 logic을, T가 Template(사용자에게 보이는 부분)을 담당하는 패턴을 말합니다. 내부 로직을 담당하는 views.py가 핵심적인 부분이라고 할 수 있어요. 사용자에게 요청을 받아서 post에 대한 CRUD의 로직을 만드는 겁니다. 예제 코드의 함수들이 꽤 낯설었지만 천천히 공부하니 생각보다 어렵지 않았습니다. 사실 어려웠어요
def home(request):
posts = Post.objects.all()
paginator = Paginator(posts, 10)
pageNum = request.GET.get("page")
posts = paginator.get_page(pageNum)
return render(request, "home.html", {"posts": posts})
models.py에서 Post 모델을 생성했죠? posts에 Post객체들을 전부 가져와서 담아줍니다.
Paginator()를 이용하여 posts를 10개씩 페이지를 나눠줘요.
GET방식으로 몇 페이지인지 가져와주고요,
그 page의 포스트들을 posts에 넣어줍니다.
return 하는데, render() 함수로 home.html을 사용자에게 보여줍니다.
이런 식으로 한 줄씩 찾아봐가며 코드를 이해해 나갔습니다.
def post_create(request):
title = request.POST.get("title")
body = request.POST.get("body")
date = request.POST.get("date")
category = Category.objects.get(pk=request.POST.get("category"))
post = Post.objects.create(title=title, body=body, date=date, category=category)
return redirect(reverse("post_detail", args=[post.pk]))
post를 생성하는 함수입니다. post를 생성하고 return 해줍니다.
그런데 render()를 쓰지 않고 redirect()를 썼네요?
그리고 reverse()와 args=[post.pk]가 무엇인지 잘 모르겠습니다.
render() vs redirect()
render()는 html파일을 받아서 화면에 띄워주는 역할을 합니다. 템플릿을 불러와요.
반면에 redirect()는 URL로 이동시켜 주는 역할을 합니다.
urls.py에서 지정한 url로 이동시켜 주고, 그 url에 지정된 view가 실행됩니다.
그러고 나서 render()할지, 다시 redirect()할지 정해지는 거예요.
저는 render()와 redirect()의 차이를 잘 몰라서 조금 헤맸습니다.
render()는 http status code 200(성공)을 반환합니다.
redirect()는 http status code 304(redirection)를 반환합니다.
이것을 잘 염두에 두고 코드를 작성해야 해요.
reverse()가 뭐지?
chatGPT에게 물어보니 이렇게 답변하네요.
그러니까, urls.py에서 정한 url의 이름을 넣으면 그 url로 이동한다는 뜻이네요. args로 인수도 전달할 수 있고요.
pk에 대해서
chatGPT야, pk에 대해 알려줘.
레코드를 구분하는 고윳값이 primary key, 즉 pk였군요.
return redirect(reverse("post_detail", args=[post.pk])의 뜻은 결국
"post_detail이라고 이름 지은 url에 post의 고윳값을 인자로 전송해 줘"
정도가 되겠습니다.
이런 식으로 update, delete 기능까지 구현하고 tests.py 코드를 작성했어요.
과제에 첨부된 예제 코드를 보다가 이해가 잘 되지 않아 chatGPT에게 테스트 코드 작성을 부탁했습니다.
그런데 chatGPT도 자꾸 틀리더라고요.
어떤 식으로 접근해야 하는지 감만 잡고 직접 테스트 코드를 작성했습니다.
def setUp(self):
# create dummy data
self.user = User.objects.create_user(username="test", password="test")
self.blog = Blog.objects.create(blogName="Test Blog", user=self.user)
self.category = Category.objects.create(
categoryName="Test Category", blog=self.blog
)
self.post = Post.objects.create(
title="Test Post", body="Test body", category=self.category, date="2020-01-01"
)
먼저 더미 데이터를 생성했습니다.
예제 코드에서는 Client를 import 해서 사용하던데, 저는 모델을 작성할 때 User를 import 해서 작성했습니다.
이 부분에서 자꾸 에러가 생겼어요.
어떻게 할지 고민하다가 결국 self.user는 User객체를 생성했습니다.
그리고 다른 테스트 함수에서는 client객체를 생성해서 에러를 고쳤습니다.
def test_post_create(self):
response = self.client.post(reverse('post_create'), {
'title': 'New Post',
'body': 'This is a new post.',
'date': '2023-05-23',
'category': 'newCatagory'
})
self.assertEqual(response.status_code, 302)
self.assertEqual(Post.objects.count(), 2)
처음에는 이렇게 작성했었어요.
자꾸 category에는 Category형식만 들어올 수 있다고 에러가 떴습니다.
도무지 이해가 안 돼서 멋사 대표님께 여쭤봤습니다.
대표님과 한참 머리 싸매고 고민하다가 문제점을 찾았어요.
우리가 블로그를 포스팅할 때, 이미 있는 카테고리에 글을 작성하지 카테고리를 생성하지는 않잖아요?
그래서 아래와 같이 코드를 바꿔주었습니다.
def test_post_create_view(self):
client = Client()
data = {"title": "Test Post", "body": "Test body", "category": self.category.pk}
response = client.post(reverse("post_create"), data)
self.assertEqual(response.status_code, 302)
이미 있는 카테고리, 즉 self.category의 pk를 넣어주니 정상적으로 테스트를 통과했습니다.
사실 이것들 말고도 많은(아주 많은) 문제들이 있었는데, 기록을 해놓지 않으니 잘 기억이 나지 않네요.
기록을 습관화해서 최대한 많은 것들을 적을 수 있도록 노력하겠습니다.
그리고 저도 아직 배우는 입장이다 보니 틀린 부분이 있을 수도 있어요(아마 있을 거라 생각해요).
언제든지 댓글로 지적해 주시면 바로 수정하도록 하겠습니다.