[빌리지 프로젝트] UI, DB 모델 설계

wodnr_P·2023년 8월 12일
0

📌 진행 상황

오늘은 이전에 진행 중이던 UI 설계를 대부분 마무리 짓고, 초기 DB 모델을 설계 했습니다.

🖥️ UI 설계

아직 기초적인 작업이라 언제든지 변경 될 가능성이 크지만 현재까지 마무리 된 UI는 다음과 같습니다.

  • 초기 랜딩페이지는 개발 마무리 단계에서 배포 직전에 마무리하는 것을 목표로 잡아서 아직은 미완성 상태입니다.
  • 로그인 UI는 Oauth를 구현해보며 디테일적인 부분을 조금 변경할 계획입니다.
  • 최대한 간단하게 표현하려고 한 탓인지 빈 공간이 많은 느낌이 들지만, 이후 프론트 개발에서 디테일을 수정할 계획을 하고 UI 설계는 빠르게 마무리 지었습니다.

📂 DB 설계

현재 기초 DB설계 한 것을 임시 ERD형식으로 간단히 표현한 것은 다음과 같습니다.

ERD

User : 관리자 및 사용자 DB Table
Board : 공지 게시판 DB Table
Comments : 공지 게시판 댓글 관련 DB Table
Vote : 게시판의 투표 관련 DB Table
Choice : 투표 항목 관련 DB Table
Account : 관리비 장부 관련 DB Table

  • 초기에는 User 모델과 관리자 User 모델을 분리하여 멀티 유저 모델을 설계 했으나 Django는 멀티 유저 모델을 지원하지 않는 다는 것을 알게 되었고, 관리자인지 일반 사용자인지 구분을 해주기 위해서 admin_check라는 bool 필드를 추가하여 User 모델을 그림과 같이 하나로 합치게 되었습니다.

  • 한 명의 사용자는 여러 개의 게시판을 관리할 수 있으므로 1:N 관계를 가지고 있습니다. 그래서 외래키를 활용하여 Board 모델에서 User 모델과 관계를 맺어주었습니다.

  • 하나의 게시글에 대해 여러 개의 댓글을 가질 수 있으므로 1:N의 관계를 가지고 있습니다. 따라서 외래키를 활용하여 Comment 모델과 Board 모델의 관계를 맺어주었습니다. 또 한 명의 사용자는 여러 개의 댓글을 작성 할 수 있기에 1:N의 관계를 맺어주었습니다.

  • 하나의 게시글에서는 하나의 투표만 생성할 수 있도록 설계 했으며, 하나의 투표에 대해 투표 항목은 여러가지를 가질 수 있으므로 각각 1:1, 1:N 관계를 맺어주었습니다. Django에서 1:1의 관계를 나타내는 Field는 OneToOneField 입니다.

  • 관리비 장부 또한 한 명의 사용자가 여러 개의 내역을 작성할 수 있으므로 1:N 관계를 맺어주었습니다.

Django 프로젝트 및 DB Model 생성

Django 프로젝트를 생성하고 Django 앱은 크게 user, board, vote, account로 나누어 생성 했습니다.

WHY❓

앱을 나눈 기준은 주요 기능을 기준으로 나누었습니다.

Django는 MTV 패턴으로, MTV=MVC와 대칭되는 디자인 패턴을 지닌 프레임워크입니다. 따라서 주요 로직을 작성하는 V(MVC 패턴에서는 C에 해당)는 Django 앱 디렉토리의 views.py 파일에서 작성하게 됩니다.

그래서 주요 기능들의 로직을 분리하기 위해 앱을 사용자 관련, 게시판 관련, 투표 기능 관련, 관리비 장부 관련으로 나누게 되었습니다.

각 DB 모델은 우선 설계한 ERD를 참고하여 다음과 같이 작성했습니다.

# user/manager.py

from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import gettext_lazy as _


class CustomUserManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifiers
    for authentication instead of usernames.
    """
    def create_user(self, email, password, **extra_fields):
        """
        Create and save a User with the given email and password.
        """
        if not email:
            raise ValueError(_('The Email must be set'))
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError(_('Superuser must have is_staff=True.'))
        if extra_fields.get('is_superuser') is not True:
            raise ValueError(_('Superuser must have is_superuser=True.'))
        return self.create_user(email, password, **extra_fields)
# user/models.py

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from .managers import CustomUserManager

class CustomAbstractBaseUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(('email address'), max_length=255, unique=True) # 이메일
    building_code = models.CharField(max_length=255, null=True)				  # 건물 별 고유 코드
    building_num = models.CharField(max_length=20, null=True)                 # 건물 호수
    building_name = models.CharField(max_length=100, null=True)               # 건물 이름
    admin_check = models.BooleanField(default=False, null=True)               # 관리자or사용자 여부 확인

    is_active = models.BooleanField(default=True)    
    is_admin = models.BooleanField(default=False)    
    is_superuser = models.BooleanField(default=False)    
    is_staff = models.BooleanField(default=False) 

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.email

📌 User 모델은 Django에서 지원 해주는 기본 모델에서 불필요한 항목이 많은 것을 판단했습니다.

그래서 AbstractBaseUser를 상속하여 이메일 인증을 위해 email로 기본 항목을 수정해주었고, AbstractBaseUser를 활용하기 위해서는 BaseUserManager의 커스텀도 필요해서 CustomUserManager 클래스에서 BaseUserManager를 상속 받아 설정을 마무리 했습니다.

# board/models.py

from django.db import models
from user.models import CustomAbstractBaseUser
# Create your models here.
class Board(models.Model):
    title = models.CharField(max_length=255)                                    # 게시글의 제목
    body = models.TextField()                                                   # 게시글의 내용
    create_time = models.DateTimeField(auto_now_add=True)                       # 게시글의 생성일자 
    user = models.ForeignKey(CustomAbstractBaseUser, on_delete=models.CASCADE)  # 사용자 모델 외래키

    def __str__(self):
        return self.title

class Comments(models.Model):
    content = models.CharField(max_length=255)                   # 댓글 내용
    create_time = models.DateTimeField(auto_now_add=True)        # 댓글 생성 시간
    board = models.ForeignKey(Board, on_delete=models.CASCADE)   # 게시글 외래키
    commenter = models.ForeignKey(CustomAbstractBaseUser, related_name="+", on_delete=models.CASCADE, blank=True)
    # 사용자 외래키
    def __str__(self):
        return self.board
# vote/models.py

from django.db import models
from board.models import Board
# Create your models here.
class Vote(models.Model):
    title = models.CharField(max_length=100)                        # 투표 주제
    create_time = models.DateTimeField(auto_now_add=True)           # 투표 생성 시간
    board = models.OneToOneField(Board, on_delete=models.CASCADE)   # 게시글 외래키

    def __str__(self):
        return self.title

class Choice(models.Model):
    count = models.IntegerField(default=0)                           # 투표 수
    content = models.CharField(max_length=100)                       # 투표 항목 내용
    vote = models.ForeignKey(Vote, on_delete=models.CASCADE)         # 투표 외래키
 
    def __str__(self):
        return self.vote
# account/models.py

from django.db import models
from user.models import CustomAbstractBaseUser
# Create your models here.

class Account(models.Model):
    plus_cash = models.IntegerField(null=True)               # 수납한 금액
    minus_cash = models.IntegerField(null=True)              # 사용한 금액
    total_cash = models.IntegerField(null=True)              # 총 금액
    explain = models.CharField(max_length=100)               # 내역
    memo = models.TextField(null=True)                       # 기타 메모 사항
    create_time = models.DateTimeField(auto_now_add=True)    # 장부 생성 날짜
    designate_date = models.DateField()                      # 거래 발생 시간 지정
    admin_user = models.ForeignKey(CustomAbstractBaseUser, on_delete=models.CASCADE)  # 사용자 외래키

    def __str__(self):
        return self.explain

회고

UI 설계를 빠르게 마무리 할 수 있어서 좋았습니다.

DB 설계는 항상 꼼꼼히 따져보지만 막상 DB 모델 생성시 다시 추가해야 할 상황이 생기는 것 같습니다. 그래서 조금 더 신중히, 조금 더 고민 해보며 설계를 해야겠다고 생각했습니다.

더 복잡한 DB를 설계 할 때에는 여러 테이블의 관계에 대해 생각을 메모하며 작성하는 것이 덜 헷갈리고, 생각을 정리함에 있어서 더 유리할 것 같다고 느꼈습니다.

Django는 멀티 유저 모델을 지원하지 않는다는 사실을 알게 되었고, 멀티 유저 모델을 지원하는 프레임워크가 무엇인지 궁금해졌습니다.

잘못된 부분이 있거나 질문이 있으시면 언제나 댓글 환영입니다 :D

profile
발전하는 꿈나무 개발자 / 취준생

0개의 댓글