본문 바로가기
부트캠프TIL, WIL/AI웹개발(스파르타코딩클럽)

[AI웹개발][60일차TIL] 쇼핑몰 상품 모델링하기

by 우지uz 2023. 6. 13.

AI 웹개발 - 60일차 TIL : 상품 모델링하기, [6월 9일]

목차
1. 상품 모델링에 대해서
2. 모델링에 대해 어려움을 느낀 부분
3. 해결하기 위한 시도(고민해본 것, 검색 및 질문을 통한 결정)
4. 느낀점

1. 상품 모델링에 대해서 

제가 생각한 상품 모델링은 

상의, 하의, 신발 등으로 카테고리를 나누고

상의, 하의, 신발대로 각각의 필드가 있는 모델링이었습니다. 

상의, 하의, 신발 각각 상품 모델을 상속받아
좀 더 디테일한 필드들을 추가 시켜서, 상세한 모델링을 하고 싶었으나
캠프 기간이 끝나고, 실제로 쇼핑몰을 운영하게 될 때 더 해보려고 합니다!

처음에는 상품 모델을 상속받아, 상의와 하의 모델을 하려고 했습니다. 

class ProductArticle(models.Model):
    class Meta:
        db_table = "product"

    product_name = models.CharField("상품 이름", null=False, max_length=100, unique=True)
    product_price = models.PositiveIntegerField("상품 가격", null=False)
    product_stuck = models.PositiveIntegerField("재고 수량", null=False)
    product_explane = models.TextField(verbose_name="내용")
    product_registed_at = models.DateTimeField(auto_now_add=True, verbose_name="생성 시간")
    product_updated_at = models.DateTimeField(auto_now=True, verbose_name="수정 시간")
    product_likes = models.ManyToManyField(
        User, verbose_name="좋아하는 상품", symmetrical=False, related_name='like_products', blank=True
        ) # symmetrical 대칭 여부 False, 유저->상품(O), 상품->유저(X)
    category = models.ForeignKey(
        Category, verbose_name="상품 종류", null=True, related_name="categorized_products",
        on_delete=models.SET_NULL
        )
    product_img = models.ImageField(
        upload_to=rename_imagefile_to_uuid, verbose_name="상품 이미지", blank=True, null=True
    )

    def __str__(self):
        return str(self.product_name)
        
class ClothingArticle(ProductArticle):
    sleeve_length = models.CharField("소매 길이", max_length=50)
    fabric_type = models.CharField("원단 종류", max_length=50)

    class Meta:
        verbose_name = "의류"
        verbose_name_plural = "의류"


class FootwearArticle(ProductArticle):
    shoe_type = models.CharField("신발 형태", max_length=50)
    heel_height = models.PositiveIntegerField("굽 높이")

    class Meta:
        verbose_name = "신발"
        verbose_name_plural = "신발"

그런데, 생각해보면 상품 판매자로부터
모든 상의 상품의 소매 길이, 원단 종류
모든 하의 상품의 신발 형태, 굽 높이를 파악하는 것은 번거로운 일이고

오히려 게시글 내용에서 상품에 대한 상세한 정보들을 기입해주는 것이
간편하다 판단이 되어서 단순하게 상품 모델링만 하도록 결정했습니다. 

# 상품 모델링
class Product(models.Model):
    class Meta:
        db_table = "product"
    PRODUCT_TYPE = [
        ("상의", "상의"),
        ("하의", "하의"),
        ("신발", "신발"),
        ("etc", "기타등등"),
    ]
    product_type = models.CharField("상품 종류", choices=PRODUCT_TYPE, null=False, max_length=30,blank=False)
    product_name = models.CharField("상품 이름", null=False, max_length=100, unique=True)
    product_price = models.PositiveIntegerField("상품 가격", null=False)
    product_info = models.TextField(verbose_name="상품 정보")
    product_registed_at = models.DateTimeField(auto_now_add=True, verbose_name="생성 시간")
    product_updated_at = models.DateTimeField(auto_now=True, verbose_name="수정 시간")
    product_likes = models.ManyToManyField(
        User, verbose_name="좋아하는 상품", symmetrical=False, related_name='like_products', blank=True
        ) # symmetrical 대칭 여부 False, 유저->상품(O), 상품->유저(X)
    manufacturer = models.CharField("제조사", max_length=30)
    product_img = models.ImageField(
        upload_to=rename_imagefile_to_uuid, verbose_name="상품 이미지", blank=True, null=True
    )

# ---------------- 좋아요 갯수 ------------------
    def count_product_likes(self):
        return self.product_likes.count()

    def __str__(self):
        return str(self.product_name)

내가 만들고자, 운영하고자 하는 쇼핑몰의
1. 카테고리
2. 상품 컨셉
3. 한 페이지에서 보여주고자 하는 View에 따라서
상품 모델링이 바뀌고 추가될 수도 있다는 것은 당연한 일 입니다.

이후에 상품 옵션으로 사이즈와 색상을 넣고 싶기 때문에 

class ProductSize(models.Model):
    PRODUCT_TYPE = [
        ("상의", "상의"),
        ("하의", "하의"),
        ("신발", "신발"),
        ("etc", "기타등등"),
    ]
    product_type = models.CharField("사이즈", choices=PRODUCT_TYPE, max_length=50, default="기타등등")
    size_value = models.CharField("사이즈 값", max_length=10, unique=True)

    def __str__(self):
        return str(self.product_type) + " : " + str(self.size_value)


class ProductColor(models.Model):
    color = models.CharField("색상", max_length=50, unique=True)

    def __str__(self):
        return str(self.color)


class ProductOption(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    size = models.ForeignKey(ProductSize, on_delete=models.CASCADE)
    color = models.ForeignKey(ProductColor, on_delete=models.CASCADE)
    stockquantity = models.PositiveIntegerField("재고수량", default=0)

    def __str__(self):
        return f"{self.product} - {self.size} - {self.color}"

    def decrease_stockquantity(self, stockquantity):
        if self.stockquantity >= stockquantity:
            self.stockquantity -= stockquantity
            self.save()
            return True
        return False

사이즈와 색상에 대한 모델을 따로 생성해주고, ForeignKey로 받아와 주었습니다.

사이즈와 색상을 내 마음대로 생성하고, 골라주기 위해서 입니다. 

그래서 상품 옵션에서, 상품과, 사이즈와, 색상을 넣어줄 수 있고
이제 프론트엔드에서 DB에 있는 값들을 불러와서 
카테고리별로, 색상별로 불러와줄 수 있습니다. 

상품문의와, 상품 문의에 대한 관리자 답변이 필요하기 때문에 모델링 했습니다.

# 생성 날짜 : 23년 6월 12일, 수정 날짜 : 23년 6월 13일
# 구매하든, 안하든 사용자에게 1개이상으로 마음대로 상품에 대한 문의를 할 수 있다.
# 수정 내용 : 문의는 Question 보단 Inquery가 맞다.
class ProductInquery(models.Model):
    class Meta:
        db_table = "ProductInquery"

    INQUERY_TYPE = [
        ("상품", "상품"),
        ("배송", "배송"),
        ("환불/취소", "환불/취소"),
        ("교환/반품", "교환/반품"),
        ("기타등등", "기타등등"),
    ]
    COMPLETE_OK = [
        ("답변완료", "답변완료"),
        ("미완료", "미완료"),
    ]
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
    product_name = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="product_name"
        )
    inquery_type = models.CharField(
        "상품 문의 종류", choices=INQUERY_TYPE, max_length=50, default="기타등등"
        )
    inquery_title = models.CharField("상품 문의 제목", null=False, max_length=50)
    inquery_content = models.TextField(verbose_name="문의 내용")
    is_complete = models.CharField("관리자 답변 여부", choices=INQUERY_TYPE, max_length=50, default="미완료")

    def __str__(self):
        return str(self.inquery_title)

# 생성 날짜 : 23년 6월 12일, 수정 날짜 : 23년 6월 13일
# 상품 문의에 대한 관리자 답변 모델
class ProductInqueryComment(models.Model):
    class Meta:
        db_table = "ProductInqueryComment"

    product_inquery = models.ForeignKey(
        ProductInquery, on_delete=models.CASCADE, related_name="product_inquery"
    )
    comment_title = models.CharField("관리자 댓글 제목", null=False, max_length=50)
    comment_content = models.TextField(verbose_name="관리자 댓글내용")

    def __str__(self):
        return str(self.comment_title)

2. 모델링에 어려움을 느낀 부분

- 카테고리 자체 모델링을 할 필요가 있는가 ??

11번가, 쿠팡처럼 굉장히 많은 카테고리들이 존재할 때에는 따로 모델링을 하는게 좋아보입니다.
심지어 상위 카테고리, 하위 카테고리로 나뉘어서 모델링을 하는게 좋아 보입니다. 

- 색깔 및 사이즈에 대한 "옵션"을 둔 이유

색깔 및 사이즈에 대한 옵션을 모델링 한 이유는 ,
상의와 하의, 신발과 같이 다른 카테고리는 사이즈와 색상이 다르기 때문입니다. 

상의 : 90, 100, 105, 110 
하의 : 28, 30, 32, 34, 36 
신발 : 230, 245, 270, 280 


3. 해결하기 위한 시도

- 상품 후기 및 상품 문의 글에 대한 생각 

상품 후기는 결제를 한 사용자에 대해서 1주일 이내로 1회 허용
상품 문의는 결제를 하지 않은 사용자에 대해서, 다회성 허용

양기철 매니저님 : 상품 후기는 결제와 관련이 있기 때문에, 결제 관련 앱에서 진행하시고
상품 문의는 상품 관련 앱에서 진행하면 됩니다. 

* 결론 : 결제를 했는지에 대한 여부로 "후기" , "문의" 게시글 특성이 달라지므로,
"결제"라는 관점으로 기능들을 나뉘어 볼 수 있어야 한다. 

- 상품 모델링에서 옵션들은 따로 모델링하자

다양한 옵션들, 추가 구매와 같은 옵션들도 옵션 모델에 기록하면 된다. 


4. 느낀점

백엔드 개발자입장에서 쇼핑몰 개발을 진행한다고 하면
모델링을 어떻게 하는가 ???에 대해서 생각하는게 가장 중요하다

그게 와이어 프레임과 연관되어야 한다. 

와이어 프레임과 API모델링이 이루어졌을 때
ERD와 API명세서의 기능들이 쉽게 정리될 수 있다.

 

AI웹개발 최종 S.A 노션 링크

AI웹개발 강의 자료 정리