유저 모델을 작성했으니 이번에는 게시글을 작성하는데 사용할 모델을 작성해야합니다.
지난 번에 티스토리 백업 파일을 살펴보며 티스토리에서 작성된 게시물에 필요한 속성들을 알아보았습니다.
이전에 확인한 파일을 기반으로 다음과 같은 모델을 작성했습니다.
# seolpyo_tistory/models/post.py
from django.conf import settings
from django.db import models
from django.shortcuts import resolve_url
from django.utils import timezone
from django.utils.text import slugify
use_slug = getattr(settings, 'TISTORY_SLUG', False)
class BaseCategory(models.Model):
class Meta:
abstract = True
verbose_name = '카테고리'
verbose_name_plural = '카테고리'
name = models.CharField(
verbose_name='카테고리명',
unique=True,
max_length=10,
)
parent = models.ForeignKey(
'self',
on_delete=models.PROTECT,
related_name='tistory_category_set',
null=True,
)
def __str__(self):
if self.parent: return f'{self.parent}/{self.name}'
return self.name
def get_absolute_url(self):
if self.name == '공지사항': return resolve_url('seolpyo_tistory:list_notice')
if self.name == '페이지': return '#'
if self.parent: return resolve_url('seolpyo_tistory:category', self.parent.name, self.name)
return resolve_url('seolpyo_tistory:category', self.name)
class Category(BaseCategory):
pass
class BaseTag(models.Model):
class Meta:
abstract = True
verbose_name = '태그'
verbose_name_plural = '태그'
name = models.CharField(
verbose_name='태그명',
unique=True,
max_length=19,
)
def __str__(self): return self.name
def get_absolute_url(self): return resolve_url('seolpyo_tistory:tag', self.name)
class Tag(BaseTag):
pass
def default_category():
for i in ['공지사항', '페이지', '서식',]: Category.objects.get_or_create(name=i)
return
class PostManager(models.Manager):
def get_queryset(self): return super().get_queryset().prefetch_related('author', 'category', 'tags')
class BasePost(models.Model):
class Meta:
abstract = True
verbose_name = '티스토리/글'
verbose_name_plural = '글'
ordering = ['-date_post', '-pk']
objects = PostManager()
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING,
related_name='tistory_post_set',
verbose_name='작성자',
editable=False,
)
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
related_name='tistory_post_set',
verbose_name='카테고리',
blank=True,
null=True,
default=default_category,
)
date_post = models.DateTimeField(
verbose_name='발행시간',
default=timezone.localtime,
)
slug = models.SlugField(
verbose_name='슬러그',
unique=True,
editable=use_slug,
null=True,
allow_unicode=True,
)
password = models.CharField(
verbose_name='비밀번호',
max_length=20,
blank=True,
)
is_private = models.BooleanField(
verbose_name='비공개로 설정',
default=False,
)
title = models.CharField(
verbose_name='제목',
max_length=29,
)
slug_title = models.SlugField(
verbose_name='슬러그(자동생성)',
unique=True,
editable=False,
allow_unicode=True,
)
content = models.TextField(
verbose_name='내용',
max_length=9999,
)
tags = models.ManyToManyField(
Tag,
related_name='tistory_post_set',
verbose_name='태그',
blank=True,
)
def __str__(self): return self.title
def get_absolute_url(self):
if self.category and self.category.name == '공지사항': return resolve_url('seolpyo_tistory:notice', self.pk)
if self.category and self.category.name == '페이지': return resolve_url('seolpyo_tistory:page', self.pk)
if self.category and self.category.name == '서식': return resolve_url('seolpyo_tistory:template', self.pk)
if use_slug: return resolve_url('seolpyo_tistory:detail_slug', self.slug if self.slug else self.slug_title)
return resolve_url('seolpyo_tistory:detail', self.pk)
def save(self, *args, **kwargs):
self.slug_title = slugify(self.title, allow_unicode=True)
if self.category and self.category.name == '서식': self.is_private = True
return super().save(*args, **kwargs)
class Post(BasePost):
pass
태그와 카테고리
태그와 카테고리를 각각 ManyToManyField와 ForeignKey로 연결하고, 카테고리의 경우 부모 카테고리를 선택할 수 있도록 하는 것으로 하위 카테고리를 구현했습니다.
게시글
단순히 제목과 내용, 발행시간 정도만 있으면 될 줄 알았으나, 티스토리에서 게시글, 서식, 공지사항, 페이지를 모두 같은 객체로 보관하고 있기 때문에 처음 생각보다 사용하는 필드가 많아졌습니다.
각 필드들의 설명은 다음과 같습니다.
- author: 작성자 정보입니다.
- title : 게시글의 제목입니다. 티스토리의 경우 제목 글자수에 따로 제한을 두지 않는 것으로 보이지만, 제목이 너무 길면 가독성이 떨어지고 지나치게 길게 작성할 이유가 없기 때문에 최대 29글자로 제한을 두었습니다.
- content: 게시글의 내용입니다. max_length가 필요할까 싶긴 하지만, 일단 9,999자로 제한을 해두었습니다.
- date_post: 게시글의 발행시간입니다. 글 작성을 요청한 시간이 기본값으로 지정됩니다.
- slug: 문자 주소를 사용하는 경우 사용하게 되는 슬러그입니다. 문자 주소 사용 여부는 settings.py에서 제어 가능한 변수를 이용하게 됩니다.
- slug_title: 티스토리에서 사용하는 slug(문자 주소)인데, 티스토리에서는 문자 주소를 지정하지 않는 경우 게시글 제목을 슬러그로 변환하여 사용합니다.
이를 반영하여 추가한 필드입니다. - password: 보호 글에서 사용하는 조회 비밀번호입니다.
- category: 카테고리를 선택합니다. 공지사항, 페이지, 서식은 모두 카테고리를 통해 분류합니다.
이 글의 댓글 기능은 일부러 막아놓았습니다. 궁금한 내용이 있다면 게시판을 이용해주세요!