다대일 관계 구현하기

Posted on 2021-08-25 by GKSRUDTN99
Django로 웹사이트 만들기 장고

Foreignkey로 Post에 author 필드 구현하기

1. blog/models.py에 author 필드 추가하기

User 모델을 사용해야 하므로 from django.contrib.auth.models import User로 User를 임포트 한다.
User를 이용해 author 필드를 추가한다.
그에 맞게 __str__()도 수정한다.
#blog/models.py

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


class Post(models.Model):
    title = models.CharField(max_length=30)
    hook_text = models.CharField(max_length=100, blank=True)
    content = models.TextField()

    head_image = models.ImageField(upload_to='blog/images/%Y/%m/%d', blank=True)
    file_upload = models.FileField(upload_to='blog/files/%Y/%m/%d', blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    author = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return f'[{self.pk}]{self.title} :: {self.author}'

(...생략...)

2. 마이그레이션하기

3. 사용자가 삭제되어도, Post가 함께 삭제되는 것이 아닌 author 필드만 null이 되게 하기

author 필드를 추가할 때, on_delete=models.CASCADE대신,
on_delete=models.SET_NULL을 사용하면 된다.
이때, 해당 필드는 null=True이어야 한다.

포스트 목록 페이지와 포스트 상세 페이지에 author 반영하기

1. 포스트 목록 페이지에 작성자를 추가하도록 테스트 코드 수정

# blog/tests.py

from django.test import TestCase, Client
from bs4 import BeautifulSoup
from .models import Post
# User 모델을 사용해야 하므로 임포트 한다.
from django.contrib.auth.models import User

class TestView(TestCase):
    def setUp(self):
        self.client = Client()
        # 새 유저를 생성해주는 부분
        self.user_trump = User.objects.create(username='trump', password='somepassword')
        self.user_obama = User.objects.create(username='obama', password='somepassword')

    def navbar_test(self, soup):
        navbar = soup.nav
        self.assertIn('Blog', navbar.text)
        self.assertIn('About Me', navbar.text)

        logo_btn = soup.find('a', text='Do It Django')
        self.assertEqual(logo_btn.attrs['href'],'/')

        home_btn = soup.find('a', text='Home')
        self.assertEqual(home_btn.attrs['href'], '/')

        blog_btn = soup.find('a', text='Blog')
        self.assertEqual(blog_btn.attrs['href'], '/blog/')

        about_me_btn = soup.find('a', text='About Me')
        self.assertEqual(about_me_btn.attrs['href'], '/about_me/')

    def test_post_list(self):
        response = self.client.get('/blog/')
        self.assertEqual(response.status_code, 200)
        soup = BeautifulSoup(response.content, 'html.parser')
        self.assertEqual(soup.title.text, 'Blog')
        self.navbar_test(soup)
        self.assertEqual(Post.objects.count(), 0)
        main_area = soup.find('div', id='main-area')
        self.assertIn('아직 게시물이 없습니다', main_area.text)
        # 포스트를 만들 때 author도 추가!
        post_001 = Post.objects.create(
            title='첫 번째 포스트입니다.',
            content='Hello World. We are the world.',
            author=self.user_trump,
        )
        post_002 = Post.objects.create(
            title='두 번째 포스트입니다.',
            content='1등이 전부는 아니잖아요!',
            author=self.user_obama,
        )
        self.assertEqual(Post.objects.count(), 2)
        response = self.client.get('/blog/')
        soup = BeautifulSoup(response.content, 'html.parser')
        self.assertEqual(response.status_code, 200)
        main_area = soup.find('div', id='main-area')
        self.assertIn(post_001.title, main_area.text)
        self.assertIn(post_002.title, main_area.text)
        self.assertNotIn('아직 게시물이 없습니다', main_area.text)
        # 아래가 추가된 부분
        self.assertIn(self.user_trump.username.upper(), main_area.text)
        self.assertIn(self.user_obama.username.upper(), main_area.text)

2. post_list.html에서 작성자의 이름을 표시하도록 수정!

<a href="#">작성자명 들어갈 위치(개발예정)</a>

위 부분을 아래와 같이 수정한다.

<a href="#">{{ p.author | upper }}</a>

3. 포스트 상세 페이지도 같은 방식으로 수정한다!