TIL-038 | 꾸며줘 홈즈 project(2)_modeling

Lee, Chankyu·2021년 11월 14일
1
post-thumbnail
post-custom-banner

🌈 데이터 모델링 - ERD 작성, 모델 작성

1. 모델 설계 및 ERD 작성

  • Table과 column의 명명은 누구나 이해할 수 있도록 확실하게 해야 한다.
  • Table 명은 복수로 짓고 column 명은 구체적으로 짓되 너무 길지 않도록한다. (ex. menu_name, category_name, sub_category_name 과 같이 지나치게 길고 자세하게 하는 것은 비효율적이다)
  • Many-to-Many로 참조하는 필드명은 복수로 사용하고, ForeignKey로 참조하는 필드명은 단수를 사용한다.

👉 ERD 최종 완성본

  • 모델링의 중요성은 정말 많이 들어왔지만 직접 프로젝트를 진행하며 내가 생각했던 것 보다 더 중요하다는 것을 절실히 깨달았다.
  • 기획단계에서 구상한 기능을 최대한 효율적으로 구현할 수 있도록 ERD를 작성해야 했고, 추후 views 작성시 효율적인 코드 작성이 가능하게 하는 것도 고려해야 겠다는 생각이 들었다.

2. Django app생성 및 models.py 작성

(1) core

from django.db import models

class TimeStamp(models.Model):
    created_at = models.DateTimeField(auto_now_add=True) 
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True 
  • core app을 생성하여 모든 app의 model들이 상속 받을 수 있는 모델을 작성하였다. 데이터 관리 차원에서 데이터의 생성시간, 업데이트 시간이 대부분의 테이블에 필요하기 때문에 TimeStamp 모델의 생성이 필요하다.
  • abstract = True 속성을 통해 해당 모델을 추상화 하여 DB에 테이블이 생성되지 않는다.

(2) users

from django.db import models

from core.models import TimeStamp

class User(TimeStamp):
    email        = models.CharField(max_length=100, unique=True)
    name         = models.CharField(max_length=100)
    password     = models.CharField(max_length=200)
    phone_number = models.CharField(max_length=50)
    nickname     = models.CharField(max_length=100)

    class Meta:
        db_table = 'users'

class Address(TimeStamp):
    user    = models.ForeignKey("User", on_delete=models.CASCADE)
    address = models.CharField(max_length=100)

    class Meta:
        db_table = 'addresses'
  • 집 꾸미기 사이트의 회원가입 및 로그인 창을 고려하여 작성하였다.

(3) products

from django.db import models

from core.models     import TimeStamp
from users.models    import User

class Menu(TimeStamp):
    name       = models.CharField(max_length=100)
    image_url  = models.CharField(max_length=100)
    
    class Meta:
        db_table = 'menus'

class Category(TimeStamp):
    name = models.CharField(max_length=100)
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE)

    class Meta:
        db_table = 'categories'

class SubCategory(TimeStamp):
    name     = models.CharField(max_length=100)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)

    class Meta:
        db_table = 'sub_categories'

class ProductGroup(TimeStamp):
    name            = models.CharField(max_length=50)
    company         = models.CharField(max_length=50)
    displayed_price = models.DecimalField(max_digits=10, decimal_places=3)
    discount_rate   = models.DecimalField(max_digits=5, decimal_places=3)
    sub_category    = models.ForeignKey('SubCategory', on_delete=models.CASCADE)
    delivery        = models.ForeignKey("Delivery", on_delete=models.CASCADE)

    class Meta:
        db_table = 'product_groups'

class Product(TimeStamp):
    name             = models.CharField(max_length=50)
    price            = models.DecimalField(max_digits=10, decimal_places=3)
    product_group    = models.ForeignKey('ProductGroup', on_delete=models.CASCADE)
    colors           = models.ManyToManyField("Color", related_name='products', through="ProductColor")

    class Meta:
        db_table = 'products'

class ProductImage(TimeStamp):
    image_url        = models.CharField(max_length=200)
    product_group    = models.ForeignKey('ProductGroup', on_delete=models.CASCADE)

    class Meta:
        db_table = 'product_images'

class ProductColor(TimeStamp):
    product = models.ForeignKey('Product', on_delete=models.CASCADE)
    color   = models.ForeignKey('Color', on_delete=models.CASCADE)

    class Meta:
        db_table = 'products_colors'

class Color(TimeStamp):
    name = models.CharField(max_length=50, null=True)

    class Meta:
        db_table = 'colors'

class Review(TimeStamp):
    user           = models.ForeignKey(User, on_delete=models.CASCADE)
    content        = models.CharField(max_length=500)
    star_rate      = models.DecimalField(max_digits=3, decimal_places=2)
    product_group  = models.ForeignKey('ProductGroup', on_delete=models.CASCADE)

    class Meta:
        db_table = 'reviews'

class ReviewImage(TimeStamp):
    image_url  = models.CharField(max_length=200)
    review     = models.ForeignKey("Review", on_delete=models.CASCADE)
    
    class Meta:
        db_table = 'review_images'

class Delivery(TimeStamp):
    delivery_type = models.CharField(max_length=50)
    payment_type  = models.CharField(max_length=50)
    delivery_fee  = models.DecimalField(max_digits=10, decimal_places=3)
    
    class Meta:
        db_table = 'deliveries'
  • 집 꾸미기 사이트의 경우 카테고리가 매우 세분화 되어있어 Menu, Category, SubCategory와 같이 클래스를 나누어 설정하였다.
  • ProductGroup이라는 하나의 상품 그룹 안에 여러 상품이 담겨져있는 사이특의 특성상 ProductGroup과 Product 클래스를 따로 생성하였다.
  • Products app에서 가장 고민이되고 지속적으로 수정을 했던 부분은 images, reviews, color를 ProductGroup 혹은 Product 중 어느 클래스와 매칭을 하냐 였다. 보통은 기획단계에서 확실히 정하고 모델링을 시작해야겠지만 이 프로젝트는 클론코딩 이기에 기존 사이트를 최대한 분석하여 결정하였다.
  • images Table의 분리는 국룰 이라고 할 수 있다.

(4) carts

from django.db import models
from django.db.models.fields import IntegerField

from core.models     import TimeStamp
from users.models    import User
from products.models import Product, Color

class Cart(TimeStamp):
    user       = models.ForeignKey(User, on_delete=models.CASCADE)
    product    = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity   = models.IntegerField(default=0)
    color      = models.ForeignKey(Color, on_delete=models.CASCADE)

    class Meta:
        db_table = 'carts'
  • 사이트의 특성에 따라 product, quantity, color 정보를 담을 수 있도록 하였다.

(5) orders

from django.db import models
from django.db.models.fields import IntegerField

from core.models     import TimeStamp
from users.models    import User, Address
from products.models import Product, Color

class Order(TimeStamp):
    user         = models.ForeignKey(User, on_delete=models.CASCADE)
    address      = models.ForeignKey(Address, on_delete=models.CASCADE)
    status       = models.ForeignKey("OrderStatus", on_delete=models.CASCADE)

    class Meta:
        db_table = 'orders'

class OrderItem(TimeStamp):
    order        = models.ForeignKey("Order", on_delete=models.CASCADE)
    product      = models.ForeignKey(Product, on_delete=models.CASCADE)
    color        = models.ForeignKey(Color, on_delete=models.CASCADE)
    quantity     = models.IntegerField(default=0)
    status       = models.CharField(max_length=30)

    class Meta:
        db_table = 'order_items'

class OrderStatus(TimeStamp):
    class Status(models.IntegerChoices):
        BEFORE_DEPOSIT   = 1 
        STAND_BY         = 2 
        DEPOSIT_COMPLTED = 3 
        CANCEL           = 4 

    description = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'order_statuses'

class Shipment(TimeStamp):
    order_item      = models.ForeignKey("OrderItem", on_delete=models.CASCADE)
    tracking_number = models.IntegerField(default=0)
    date            = models.DateField(auto_now=True)

    class Meta:
        db_table = 'shipments'
  • OrderStatus 클래스의 경우 Status라는 내부 클래스를 생성하여 status를 직관적으로 작성할 수 있도록 하였다. IntegerChoices 클래스는 django에서 지원하는 클래스이며, 열거형 값이 정수인 경우에 이와 같이 작성하여 직관적인 코드 작성이 가능해진다.
  • order의 모델링의 경우 현업에서 주로 쓰이는 모델링을 참고로 하였다. 기업마다 다르겠지만 공통적으로 쓰이는 모델을 아래의 사이트에서 참고하였다.

👉 참고 사이트 http://www.databaseanswers.org/data_models/e_commerce/index.htm

profile
Backend Developer - "Growth itself contains the germ of happiness"
post-custom-banner

0개의 댓글