본문 바로가기

회고록(TIL&WIL)

TIL 2022.07.13 SidePro - S.A, 모델링

👉 1. 프로젝트 기간

2022.07.07 (목) ~ 2022.08.04 (목)

 

👉 2. 팀 구성

김선민, 김민기, 박재현, 황신혜 

 

👉 3. 프로젝트 주제

주제 : 온라인 커피챗을 곁들인 개발자 사이드 프로젝트 모아보기 서비스

 

👉 4. 프로젝트 메인 기능

1. 사이드 프로젝트 게시판 (조회, 생성, 수정, 삭제)

2. 커피챗 실시간 Socket 통신 온/오프라인 

3. 유저 Tag / 주제 기반 협업 필터링

 

👉 4. 프로젝트 진행 방식

  • 화면 기획 (Figma) : 링크 (완료)
  • API 설계 (Notion) : 링크 (완료)
  • 일정 관리 (갠트 차트) : 링크 (완료)
  • 기능 구현 관리 (Git Issue) : 링크 (진행중)

 

👉 5. 화면 와이어프레임 및 기능 범위 정의 (진행중)

화면 화면 이름 기능
첫 화면  
  로그인
페이지
소셜로그인
  회원가입
페이지
 
마이
페이지
유저가 프로젝트(게시글) 조회

유저가 북마크한 게시글 조회
유저프로필 수정 페이지 유저 프로필 정보 수정

수정 내용은 추천 알고리즘 등에 반영
메인페이지
(게시판)
베너 (이벤트)-이달의 최우수 프로젝트 등

프로젝트(게시글) 목록 조회 (북마크, 댓글갯수)

프로젝트(게시글) 목록 조회 (커피챗 하기 버튼)

프로젝트(게시글) 목록 필터 조회

프로젝트(게시글) 목록 검색 조회

우측 하단 프로젝트(게시글) 등록하러 가기

우측 하단 커피챗 내역 확인

User Based 추천 프로젝트 결과 조회
메인페이지
(게시판
등록)
프로젝트(게시글) 기본 정보(기술스택, 썸네일) 입력

Toast UI Editor활용 Markdown기반 글 작성 

상세페이지
(게시글
조회)
프로젝트(게시글) 상세 페이지 조회

프로젝트(게시글) 수정, 삭제하기

댓글 등록 및 수정

댓글 삭제

메인 페이지
(채팅)
프로젝트 채팅 창 조회

채팅 창 User 클릭시 User 정보 조회 모달

채팅 창 내역 더블클릭 시 실시간 채팅창 on

실시간 채팅 Socket 통신 구현


 

👉 6. DB 설계도 작성

 

 

# user/models.py
from ast import Constant
from asyncio import constants
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from user import constants

class MeetTime(models.Model):        
    # 주중 선호, 주말 선호, 상관없음
    TIME_CHOICE = constants.TIME_CHOICE
    time_type = models.CharField("선호 시간대", choices=TIME_CHOICE, max_length=50)

    class Meta:
        db_table = "MEETTIME"

class Region(models.Model):
    REGION_CHOICE = constants.REGION_CHOICE
    name = models.CharField('활동지역', choices=REGION_CHOICE, max_length=50)

    class Meta:
        db_table = "REGION"

class Skills(models.Model):
    SKILLS_CHOICE = constants.SKILLS_CHOICE
    name = models.CharField('기술스택', choices=SKILLS_CHOICE, max_length=20)
        
    class Meta:
        db_table = "SKILLS"

# custom user model 사용 시 UserManager 클래스와 create_user, create_superuser 함수가 정의되어 있어야 함
class UserManager(BaseUserManager):
    def create_user(self, email, password=None):
        if not email:
            raise ValueError('Users must have an email')
        user = self.model(
            email=email,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
    
    # python manage.py createsuperuser 사용 시 해당 함수가 사용됨
    def create_superuser(self, email, password=None):
        user = self.create_user(
            email=email,
            password=password
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

class User(AbstractBaseUser):
    email = models.EmailField("이메일", max_length=150, unique=True)
    password = models.CharField("비밀번호", max_length=300)
    username = models.CharField("이름", max_length=30)
    join_date = models.DateTimeField("가입일", auto_now_add=True)
    
    bookmark = models.ManyToManyField("project.Project", related_name="bookmarks")

    is_active = models.BooleanField(default=True) # 계정활성화 여부
    is_admin = models.BooleanField(default=False) # 관리자 계정 여부

    USERNAME_FIELD = 'email' # 로그인 시 사용할 필드 지정
    REQUIRED_FIELDS = [] # createsuperuser 할 때 추가로 요구할 필드 지정
    
    objects = UserManager() # custom user 생성 시 필요

    def __str__(self):
        return self.username

    # 로그인 사용자의 특정 테이블의 crud 권한을 설정, perm table의 crud 권한이 들어간다.
    # admin일 경우 항상 True, 비활성 사용자(is_active=False)의 경우 항상 False
    def has_perm(self, perm, obj=None):
        return True
    
    # 로그인 사용자의 특정 app에 접근 가능 여부를 설정, app_label에는 app 이름이 들어간다.
    # admin일 경우 항상 True, 비활성 사용자(is_active=False)의 경우 항상 False
    def has_module_perms(self, app_label): 
        return True
    
    # admin 권한 설정
    @property
    def is_staff(self): 
        return self.is_admin

    class Meta:
        db_table = "USER"

class UserProfile(models.Model):
    user = models.OneToOneField(User, verbose_name="유저",on_delete=models.CASCADE, null=True, blank=True)
    description = models.TextField("자기소개", null=True, blank=True)
    profile_image = models.FileField(null=True, blank=True)
    github_url = models.URLField(verbose_name = "GITHUB URL", null=True, blank=True)
    skills = models.ManyToManyField(Skills, verbose_name='기술 스택')
    meet_time = models.ForeignKey(MeetTime, verbose_name="가능시간", on_delete=models.CASCADE, null=True, blank=True)
    region = models.ForeignKey(Region, verbose_name="활동지역", on_delete=models.CASCADE, null=True, blank=True)
    
    def __str__(self):
        return self.user.username

    class Meta:
        db_table = "USERPROFILE"

MeetTime, Region, Skills 모델을 정의할 때 choice를 사용했는데 사용한 상수는 constant.py를 새로 정의해서 불러오도록 만들었다.

REGION_CHOICE = (
        ("서울", "서울"), ("경기", "경기"), ("인천", "인천"), ("세종", "세종"), ("강원", "강원"), 
        ("충북", "충북"), ("충남", "충남"), ("전북", "전북"), ("전남", "전남"), ("광주", "광주"), 
        ("대전", "대전"), ("대구", "대구"), ("부산", "부산"), ("울산", "울산"), ("제주", "제주")
)    
TIME_CHOICE = (
        ("주중 선호", "주중 선호"), ("주말 선호", "주말 선호"), ("상관없음", "상관없음")
)
SKILLS_CHOICE = (
(".NET",".NET"),
("ABAP","ABAP"),
("AIX","AIX"),
...
)
# project(app)/models.py
from datetime import timedelta
from datetime import datetime
from django.db import models
from user.models import User, Skills


# 프로젝트(게시글)
class Project(models.Model):
    user = models.ForeignKey(User, verbose_name="작성자", on_delete=models.CASCADE)
    title = models.CharField("제목", max_length=50)
    skills = models.ManyToManyField(Skills, verbose_name="카테고리")
    thumnail_img_path = models.FileField(upload_to="", verbose_name="썸네일")
    content = models.TextField("글내용")
    count = models.PositiveIntegerField("조회수")
    github_url = models.URLField("레포지토리주소")
    created_date = models.DateTimeField("생성날짜", auto_now_add=True)
    updated_date = models.DateTimeField("수정날짜", auto_now=True)
    
    def __str__(self):
        return self.title
    
    class Meta:
        db_table = "PROJECT"

# 댓글
class Comment(models.Model):
    user = models.ForeignKey(User, verbose_name="작성자", on_delete=models.CASCADE)
    project = models.ForeignKey(Project, verbose_name="게시글", on_delete=models.CASCADE)
    comment = models.TextField("댓글내용")
    created_date = models.DateTimeField("작성날짜", auto_now_add=True)
    updated_date = models.DateTimeField("수정날짜", auto_now=True)
    
    def __str__(self):
        return (f"{self.user} / {self.project} / {self.comment}")
    
    class Meta:
        db_table = "COMMENT"
# chat/models.py
from django.db import models
from user.models import User


# 채팅방 상태
class Status(models.Model):
    # open, close
    STATUS_CHOICE = (
        ("open", "Open"),
        ("close", "Close"),
    )
    status = models.CharField(choices=STATUS_CHOICE, verbose_name="채팅방 상태", max_length=20)
    
    def __str__(self):
        return self.status

    class Meta:
        db_table = "STATUS"

# 채팅방 정보
class Room(models.Model):
    owner = models.ForeignKey(User, verbose_name="본인", related_name = "owner", on_delete=models.CASCADE)
    opponent = models.ForeignKey(User, verbose_name="채팅상대", related_name = "opponent", on_delete=models.CASCADE)
    status = models.ForeignKey(Status, verbose_name="채팅방 상태", on_delete=models.CASCADE)
    lasted_time = models.DateTimeField("마지막 메시지 시간", auto_now=True)
    lasted_message = models.TextField("마지막 메세지")
    
    def __str__(self):
        return f"{self.owner.username}, {self.opponent.username}의 채팅방"

    class Meta:
        db_table = "ROOM"

# 채팅방 내용
class Chat(models.Model):
    room = models.ForeignKey(Room, verbose_name="채팅방 정보", on_delete=models.CASCADE)
    send_user = models.ForeignKey(User, verbose_name="보낸이", related_name = "send_user", on_delete=models.CASCADE)
    receive_user = models.ForeignKey(User, verbose_name="받은이", related_name = "receive_user", on_delete=models.CASCADE)
    send_time = models.DateTimeField("보낸일시", auto_now=True)
    message = models.TextField("메세지")

    def __str__(self):
        return self.room

    class Meta:
        db_table = "CHAT"