23.Django(장고) - ecommerce 프로젝트 - 게시판 - 글쓴이 추가 및 모델 변경

JungSik Heo·2024년 12월 6일

1.글쓴이 추가해 보기

게시판의 질문, 답변에는 누가 글을 작성했는지 알려주는 "글쓴이" 항목이 필요하다. 이번에는 "글쓴이"에 해당되는 author 속성을 추가해 보자.

boards\models.py

from django.db import models
from django.contrib.auth.models import User


class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE) 
    (... 생략 ...)

user 필드는 User 모델을 ForeignKey로 적용하여 선언했다. User 모델은 django.contrib.auth 앱이 제공하는 사용자 모델로 회원 가입시 데이터 저장에 사용했던 모델이다. on_delete=models.CASCADE는 계정이 삭제되면 이 계정이 작성한 질문을 모두 삭제하라는 의미이다.

기억날지 모르겠지만 모델을 변경한 후에는 반드시 makemigrations와 migrate를 통해 데이터베이스를 변경해 주어야 한다. 다음과 같이 makemigrations을 실행하자.

하지만 makemigrations을 실행하면 option을 선택하라는 위와 같은 메시지가 나타난다.

이 메시지가 나타난 이유는 Post 모델에 user를 추가하면 이미 등록되어 있던 게시물에 user에 해당되는 값이 저장되어야 하는데, 장고는 user에 어떤 값을 넣어야 하는지 모르기 때문이다. 그래서 장고가 여러분에게 기존에 저장된 Post 모델 데이터의 user에 어떤 값을 저장해야 하는지 묻는 것이다.

이 문제를 해결하는 방법에는 2가지가 있다. 첫 번째 방법은 user에 속성을 null로 설정하는 방법이고, 두 번째 방법은 기존 게시물에 추가될 user에 강제로 임의 계정 정보를 추가하는 방법이다. 질문, 답변에는 user에 값이 무조건 있어야 하므로 두 번째 방법을 사용할 것이다.

입력한 '1'은 admin 계정의 id 값이다. 따라서 기존 게시물의 user에는 admin 계정이 등록될 것이다

계정 생성시마다 id가 1부터 순차적으로 증가한다. 따라서 우리가 createsuperuser로 최초 생성했던 계정인 admin의 id 값은 1이다.

migrate 명령으로 변경된 내용을 데이터베이스에 적용하자.

python manage.py migrate

2.comment 속성 추가

Post 모델과 같은 방법으로 Comment 모델에 author 속성을 추가하자.

# 댓글 관련 테이블
class Comment(models.Model):
    user       = models.ForeignKey(User, on_delete=models.CASCADE)

makemigrations 명령을 실행하면 다음처럼 Post 모델과 동일한 선택 메시지가 나타날 것이다. 역시 동일한 방법으로 1)을 선택하고 admin의 id 값인 1을 입력하자.

Post속성에 null 허용하기
추가한 user 속성에 null을 허용하려면 다음처럼 null=True 속성을 추가하면 된다.
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)

  • null=True 속성을 부여하면 migrate시 데이터베이스에 null 허용 컬럼으로 생성된다

user 저장

이제 Post, Comment 모델에 user 속성이 추가되었으므로 질문과 답변 저장시에 user도 함께 저장해야 한다.

질문, 답변에 글쓴이를 추가한다는 느낌으로 작업을 진행하자.

comment_create 함수를 추가하자.

boards\views.py

def comment_create(request, question_id):
    (... 생략 ...)
 comment = form.save(commit=False) # 임시 저장하여 post 객체를 리턴받는다.
            comment.user = request.user
            comment.post = post
            (... 생략 ...)
    (... 생략 ...)
def post_create(request):
    (... 생략 ...)
                post = form.save(commit=False) # 임시 저장하여 post 객체를 리턴받는다.
            post.user = request.user  # author 속성에 로그인 계정 저장
            post.save()# 데이터를 실제로 저장한다.
            (... 생략 ...)
    (... 생략 ...)

로그인이 필요한 함수

이 오류는 request.user가 User 객체가 아닌 AnonymousUser 객체라서 발생한 것이다. 조금 더 자세히 설명하자면 request.user에는 로그아웃 상태이면 AnonymousUser 객체가, 로그인 상태이면 User 객체가 들어있는데, 앞에서 우리는 user 속성을 정의할 때 User를 이용하도록 했다. 그래서 post.author = request.user에서 User 대신 AnonymousUser가 대입되어 오류가 발생한 것이다.

이 문제를 해결하려면 request.user를 사용하는 함수에 @login_required 애너테이션을 사용해야 한다. @login_required 애너테이션이 붙은 함수는 로그인이 필요한 함수를 의미한다.

boards\views.py

from django.contrib.auth.decorators import login_required 
    (... 생략 ...)

@login_required(login_url='accounts:login')
def post_create(request):
            (... 생략 ...)
@login_required(login_url='accounts:login')
def comment_create(request,post_id):
    (... 생략 ...)

post_create 함수와 comment_create 함수는 함수내에서 request.user를 사용하므로 로그인이 필요한 함수이다. 따라서 위와 같이 @login_required 어노테이션을 사용해야 한다.

로그아웃 상태에서 @login_required 어노테이션이 적용된 함수가 호출되면 자동으로 로그인 화면으로 이동하게 된다. @login_required 어노테이션은 login_url='accounts:login' 처럼 로그인 URL을 지정할 수 있다.

이렇게 수정한후 로그아웃 상태에서 질문을 등록하거나 답변을 등록하면 자동으로 로그인 화면으로 이동되는 것을 확인할 수 있을 것이다.

next

그런데 로그아웃 상태에서 '질문 등록하기'를 눌러 로그인 화면으로 전환된 상태에서 웹 브라우저 주소창의 URL을 보면 next 파라미터가 있을 것이다.

이는 로그인 성공 후 next 파라미터에 있는 URL로 페이지를 이동하겠다는 의미이다. 그런데 지금은 그렇게 되고 있지 않다. 로그인 후 next 파라미터에 있는 URL로 페이지를 이동하려면 로그인 템플릿에 다음과 같이 hidden 타입의 next 항목을 추가해야 한다.

templates\accounts\login.html
아래와 같이 추가

disabled

한가지 더 생각해 봐야 할 것이 있다. 현재 댓글 등록은 로그아웃 상태에서는 아예 글을 작성할 수 없어서 만족스럽다. 하지만 댓글 등록은 로그아웃 상태에서도 글을 작성할 수 있다. 물론 댓글 작성 후 <저장하기>를 누르면 자동으로 로그인 화면으로 이동되므로 큰 문제는 아니지만 작성한 답변이 사라지는 문제가 있다.

작성한 글이 사라지는 문제를 해결하려면 로그아웃 상태에서는 아예 댓글 작성을 못하게 막는 것이 좋을 것이다.

templates\boards\post_detail.html 파일을 다음과 같이 수정하자.

    (... 생략 ...)
    <div class="mb-3">
        <label for="content" class="form-label">답변내용</label>
        <textarea {% if not user.is_authenticated %}disabled{% endif %} name="content" id="content" class="form-control" rows="10"></textarea>
    </div>
       (... 생략 ...)

profile
쿵스보이(얼짱뮤지션)

0개의 댓글