1차 프로젝트 시작(feat.IKEA)

김광일·2022년 3월 2일
0

PROJECT

목록 보기
1/5
post-thumbnail

1.프로젝트 시작!


드디어 프로젝트가 시작되었고, 3일차가 되었다. (3일차지만 이틀은 쉬었다.)
우리 조에는 프론트엔드 3명과 백엔드 2명(필자 포함)이 배정되었고, 이케아라는 사이트를 클론하게 되었다.
이름은 그대로 쓸 수 없기에 새로운 이름을 구상하던 중, 이케아의 발음과 비슷한 이케해여? 라는 이름을 사용할까..얘기가 나왔다. 물론 바뀔 수도 있다.
의미는 이케아는 가구를 직접 조립해서 사용하는 경우가 많은데, 이 조립 과정이 이게 맞아여~? 라는 말을 좀 귀엽게 꾸며낸 것이다.

2.역할분담! & ERD 작성


팀원들끼리 모여서 각자 할 일을 분담하여 trello를 작성했고, BE 측에서 가장 먼저 해야할 일은 ERD 작성이었다.

중간 과정도 있었고, 계속된 수정이 있었지만, 그 과정이 기록된 것이 없어 일단 최종적으로 결정된 것을 올린다. 앞으로 계속 수정될 수 있다 들었는데, 혹 수정이 된다면 차곡차곡 쌓아놔야겠다.
간단한 설명을 하자면, 크게는 users 와 products 두개로 앱을 나누어 작성을 할 것이다.

(1). users

  • users
    : full_name, email, password, address, phone_number 는 입력된 정보로 받고, membership의 경우는 true,false로 결정한다.
    gender를 정참조하여 N(user):1(gender)의 관계를 형성한다.

  • gender
    : gender의 경우엔 굳이 정규화를 시킨 이유를 보기 위해 1천만개의 user 데이터가 저장되어 있다고 가정해보자. 남성,여성으로 표기된 부분을 영어로 수정해야할 니즈가 생긴 경우, 정규화가 되어있지 않다면 이것을 처리하는 비용과 시간이 상당하지만 정규화를 시켜놓으면 gender 테이블의 내용만 수정해주면 되기 때문에 훨씬 간단하다.
    이렇게 작은 프로젝트에서는 큰 의미야 없겠지만 미리미리 습관을 들여놓고 장점에 대해 미리 공부하면 좋겠다 싶어 바꾸게 되었다.

  • order_products
    : 주문하는 물품에 대한 정보이다. 주문할 수량을 입력받아야하고, 그 상품을 주문한 user의 id, 아래서 나올 거지만 product_information를 통해 지점, 상품, 색상, 사이즈, 재고수량에 관한 정보를 받고, 상품의 배송상태에 대해서 전달 받는다.
    order_status를 정참조하여 N(order_products):1(order_status)의 관계를 형성한다.

  • order_status
    : 현재 배송상태에 관한 내용을 담아준다.

  • carts
    : 장바구니이다. 장바구니의 주인(user_id), 회원이 담은 물건의 정보(product_information), 그리고 그 수량을 전달 받는다.
    user와 products_infromation를 정참조한다.

(2). products

  • main_category
    : 제품을 검색할 때 가장 상위에 있는 부분이다.
    예시로 가구, 홈오피스, 침대/매트리스 등등 부분을 main으로 지정해주었다.

  • sub_category
    : main_category 의 정보를 받아 그 아래에 있는 개인용가구, 가구세트, 침대... 등등의 정보를 담아준다.
    main_category를 정참조하여 N(sub):1(main)의 관계를 형성한다.

  • products
    : 제품명, 가격, 제품상세 그리고 sub_category에 관한 정보를 전달받는다. sub_category 안에 들어가면 실제로 보이는 제품을 생각하면 된다.
    sub_category를 정참조하여 N(products):1(sub)의 관계를 형성한다.

  • images
    : 각 제품에 들어가는 image의 url을 넣어준다.
    product를 정참조하여 N(image):1(product)의 관계를 형성한다.

  • stores
    : 지점명에 관한 정보를 넣어준다.

  • colors
    : 제품 색상에 관한 정보를 넣어준다.

  • size
    : 제품 크기에 관한 정보를 넣어준다.

  • product_information
    : 각 상품에 관한 정보(product_id), 상품이 있는 지점명(store_id), 상품의 색상(color_id), 상품의 사이즈(size_id), 그리고 상품의 재고 수량에 관한 정보를 저장하는 중간테이블이다.

  • reviews
    : 고객들이 상품평을 적으면 그 정보를 받는다. 별점, 평가내용, 작성한 user와 해당 상품의 정보를 받는다.
    user와 product를 정참조하며 N(review):1(user/product)의 관계를 형성한다.

3.model 작성


나름 작성된 ERD를 가지고 users와 products 앱에서 model을 작성해준다.

# wekea/users/models.py
from django.db import models

class User(models.Model):
    full_name    = models.CharField(max_length=40)
    email        = models.EmailField(max_length=50, unique=True)
    password     = models.CharField(max_length=100)
    membership   = models.BooleanField(default=False)
    address      = models.CharField(max_length=255)
    phone_number = models.CharField(max_length=20)
    gender       = models.ForeignKey('Gender', on_delete=models.CASCADE)
    created_at   = models.DateTimeField(auto_now_add=True)
    updated_at   = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'users'


class Gender(models.Model):
    gender = models.CharField(max_length=10)

    class Meta:
        db_table = 'genders'


class OrderStatus(models.Model):
    status = models.CharField(max_length=30)

    class Meta:
        db_table = 'order_status'


class OrderProduct(models.Model):
    quantity            = models.IntegerField()
    order_status        = models.ForeignKey('OrderStatus', on_delete=models.CASCADE)
    user                = models.ForeignKey('User', on_delete=models.CASCADE)
    product_information = models.ForeignKey('products.ProductInformation', on_delete=models.CASCADE)
    created_at          = models.DateTimeField(auto_now_add=True)
    updated_at          = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'order_products'


class Cart(models.Model):
    quantity            = models.IntegerField()
    user                = models.ForeignKey('User', on_delete=models.CASCADE)
    product_information = models.ForeignKey('products.ProductInformation', on_delete=models.CASCADE)
    created_at          = models.DateTimeField(auto_now_add=True)
    updated_at          = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'carts'


class Review(models.Model):
    rating     = models.IntegerField()
    comment    = models.TextField()
    user       = models.ForeignKey('User', on_delete=models.PROTECT)
    product    = models.ForeignKey('products.Product', on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'reviews'
# wekea/products/models.py
from django.db import models

class Product(models.Model):
    name         = models.CharField(max_length=50)
    price        = models.DecimalField(max_digits=12, decimal_places=2)
    description  = models.TextField()
    sub_category = models.ForeignKey('SubCategory', on_delete=models.CASCADE)
    created_at   = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'products'


class Image(models.Model):
    image_url = models.CharField(max_length=200)
    product   = models.ForeignKey('Product', on_delete=models.CASCADE)

    class Meta:
        db_table = 'images'


class SubCategory(models.Model):
    name          = models.CharField(max_length=50)
    main_category = models.ForeignKey('MainCategory', on_delete=models.CASCADE)

    class Meta:
        db_table = 'sub_categories'


class MainCategory(models.Model):
    name = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'main_categories'


class ProductInformation(models.Model):
    product         = models.ForeignKey('Product', on_delete=models.CASCADE)
    store           = models.ForeignKey('Store', on_delete=models.CASCADE)
    color           = models.ForeignKey('Color', on_delete=models.CASCADE)
    size            = models.ForeignKey('Size', on_delete=models.CASCADE)
    remaining_stock = models.IntegerField()
    
    class Meta:
        db_table = 'product_informations'


class Store(models.Model):
    name = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'stores'


class Color(models.Model):
    name = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'colors'


class Size(models.Model):
    size = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'sizes'

4.CSV 작성


이 부분은 아직 진행중이지만, 시작을 하는데에 있어 오류가 있어 적어본다.

# wekea/db_uploader.py
import os, django, csv, sys

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wekea.settings')
django.setup()

from users.models import *
from products.models import *

CSV_PATH_DATA = './data.csv'
with open(CSV_PATH_DATA) as in_file:
    data_reader = csv.reader(in_file)
    next(data_reader)
    for row in data_reader:
        if row[1]:
            print(row[1])

이렇게 작성을 하였을 때 아래와 같은 에러가 났다.
이 해결법으로는 아래 링크를 달아두겠지만, 결과만 먼저 보자면
open("file.name", "r", encoding='euc-kr') 이 구문을 활용하면 된다.

# wekea/db_uploader.py
import os, django, csv, sys

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wekea.settings')
django.setup()

from users.models import *
from products.models import *

CSV_PATH_DATA = './data.csv'
with open(CSV_PATH_DATA, 'r', encoding='cp949') as in_file:
    data_reader = csv.reader(in_file)
    next(data_reader)
    for row in data_reader:
        if row[1]:
            print(row[1])

검색 해본 에러 해결법
해결법1
해결법2
사실 1번과 2번의 방법은 동일하다. 하지만 1번에선 pandas를 설치한 경우이고 2번의 경우엔 설치하지 않은 상태에서 적용하는 모습을 보이는 것 같다.


Tip?


프로젝트가 끝나기 전까지 모델은 필연적으로 계속해서 수정이 될 것이고, 그 때마다 마이그레이션을 하게 될텐데, 너나 할 것 없이 하게 되면 conflict 의 문제에 직면할 것이다. 그 해결 방법은 아래에 링크를 걸어둔다.

git conflict 시 해결방법
해결방법

이 부분에 관하여 우리 담당 멘토이신 승현님께서 주신 팁이라면 팁일까?
가장 좋은 방법은 사전에 예방을 하는 것!

문제 발생) 모델의 수정사항이 생겼다.

  1. 기존 마이그레이션을 한 사람이 모델 수정용으로 새로운 브렌치를 생성한다.
  2. 새로운 브렌치에서 모델을 수정한 후 이상이 있는지 확인한다.
  3. 이상이 없다면 github에 push 하여 merge 한다.
  4. 다른 팀원들이 pull 받고 다시 작업 시작.

이렇게 진행을 하면 번거로울 수는 있지만, 마이그레이션 파일이 겹치지 않아 컨플릭트가 날 확률이 현저하게 줄어든다고 한다.

아직은 해볼 기회가 없어 얼만큼 귀찮고 얼만큼 효과적인지 체감할 수 없지만, 앞으로 남은 기간동안 부딪혀 볼 기회가 있었으면 좋겠다.

profile
부족함 없이 공부하자

0개의 댓글