[Project] Lush TeamProject ๐Ÿš€

Inah-_-ยท2021๋…„ 3์›” 27์ผ
3

Projects

๋ชฉ๋ก ๋ณด๊ธฐ
1/2
post-thumbnail

Lush Project

ํด๋ก  ํ”„๋กœ์ ํŠธ๋Š” ์ˆœ์ˆ˜ ๊ฐœ๋ฐœ์‹œ๊ฐ„์˜ ๋น„์ค‘์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ด๋ฏธ ์„œ๋น„์Šค ์ค‘์ธ ์‚ฌ์ดํŠธ์˜
๊ธฐํš์ด๋‚˜ ๋””์ž์ธ์„ ํด๋ก ํ•˜์—ฌ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฒˆ์— ์ง„ํ–‰ํ•œ ํ”„๋กœ์ ํŠธ๋Š”
Clone Colding ํ”„๋กœ์ ํŠธ๋กœ, ๋ฌผ๋ก  ๋กœ์ง์ด๋‚˜ ๊ตฌํ˜„๋ฐฉ๋ฒ•์€ ์ง์ ‘ ์ฝ”๋”ฉํ•œ๋‹ค.
๋Œ€์ƒ ์‚ฌ์ดํŠธ๋Š” ๋ฐ”๋กœ ๋‚ด๊ฐ€ ์ข‹์•„ํ•˜๋Š” ๋Ÿฌ์‰ฌ!

Project ๊ธฐ๊ฐ„

2021.3.15 ~ 2021.3.26

Team Klush ๐Ÿš€

Front 3๋ช… + Back 3๋ช…

Team github

Frontend
Backend

Frontend ๊ฐœ์ธ github

๊น€ํ˜„์ค‘(PM) ์ •์žฌ์šฑ ๊น€์šฐ์˜

Backend ๊ฐœ์ธ github

์ •์ˆ˜๋นˆ ํ•œ์ง€์˜ ์ตœ์ธ์•„


Project Architecture ๐Ÿš€

AQueryTool๋กœ ๋ชจ๋ธ๋ง

๋ชจ๋ธ๋ง์„ ์ฒ˜์Œ ๊ตฌํ˜„ํ•  ๋•Œ์— ํŒ€์›๋“ค๊ณผ ๋งŽ์€ ์‹œ๊ฐ„์„ ํ• ์• ํ–ˆ๋‹ค.
๋ถ„๋ช… StarBucks ๋ชจ๋ธ๋ง์„ ํ•ด๋ดค์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ 
๊ทธ๋‹น์‹œ ์–ด๋ ค์›Œํ–ˆ๋˜ ๊ทธ ๋ชจ๋ธ๋ง์€ ์•„๋ฌด๊ฒƒ๋„ ์•„๋‹ˆ์˜€๊ตฌ๋‚˜ ์‹ถ์—ˆ๋‹ค.
์™œ๋ƒํ•˜๋ฉด order์™€ product์˜ ์ค‘๊ฐ„ํ…Œ์ด๋ธ”์ธ orderproduct ์ฆ‰ '์žฅ๋ฐ”๊ตฌ๋‹ˆ'์˜ ForeignKey์™€ M2M์˜ ๊ด€๊ณ„๊ฐ€ ๋„ˆ๋ฌด๋‚˜๋„ ํ—ท๊ฐˆ๋ ธ๋‹ค.

์›๋ž˜ ์ฒ˜์Œ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ๋ชจ๋ธ๋ง์— ์ œ์ผ ๋งŽ์€ ์‹œ๊ฐ„์ด
์“ฐ์—ฌ์ง„๋‹ค๊ณ  ๋“ค์—ˆ๋Š”๋ฐ ๊ทธ๊ฒŒ ์ •๋ง ๋งž๋Š” ๋ง์ด์˜€๋‹ค.

ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„ 3์ผ์ด ์ง€๋‚ฌ์„ ๋•Œ์—๋„ ๋ชจ๋ธ๋ง์ด ํ—ท๊ฐˆ๋ ค
์ œ๋Œ€๋กœ ๋œ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜์ง€ ๋ชปํ–ˆ์—ˆ๋‹ค.

๋˜, ์ค‘๊ฐ„์ค‘๊ฐ„ ๋งŽ์€ ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•˜์˜€๋‹ค.
table์˜ ๋ช…์ด๋ผ๋˜๊ฐ€, table์˜ ์ƒํƒœ, ํ•„์š” ๋ถ€๋ถ„์„ ์ƒ๊ฐํ•˜๋ฉฐ
๋‹ค์‹œ ์ˆ˜์ •ํ•œ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฌผ๋กœ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๊ธฐ ๊นŒ์ง€ ๊ฑฐ์ง„ 1์ฃผ์ผ์ด ๊ฑธ๋ ธ๋‹ค.

MySQL

์šฐ๋ฆฌํŒ€์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์„ ๋•Œ csvํŒŒ์ผ์„ python์œผ๋กœ DB์— ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ์‹์„ ํƒํ–ˆ๋‹ค.
์ด ๋ถ€๋ถ„์€ ๋‚ด๊ฐ€ ๋งก์•˜๋Š”๋ฐ ๋„ˆ๋ฌด๋‚˜ ์žฌ๋ฐŒ๋Š” ๊ฒƒ ใ… ใ… ใ… ๐Ÿ˜†
Products์˜ table data๊ฐ€ ๋“ค์–ด์˜จ ๊ฑธ ๋ดค์„ ๋•Œ์˜ ์พŒ๊ฐ์ด๋ž€...๐Ÿ‘

import os
import django
import csv
import sys

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

from product.models import (
	Menu,
    	Category,
        SubCategory,
        Product,
        Image,
        Label,
        ProductLabel
        )

with open(CSV_PATH_PRODUCTS) as in_file:
    data_reader = csv.reader(in_file)
    next(data_reader, None)
    for row in data_reader:
        product = Product.objects.create(
            sub_category = SubCategory.objects.get(name=row[2]),
            name         = row[3],
            is_new       = int(row[4]),
            is_vegan     = int(row[5]),
            is_soldout   = int(row[6]),
            price        = float(row[7]),
            weight       = float(row[8])
        )
with open(CSV_PATH_PRODUCTS) as in_file:
    data_reader = csv.reader(in_file)
    next(data_reader, None)
    for row in data_reader:
        Image.objects.create(image_url = row[9][1:-1], product = Product.objects.get(name=row[3]))


์ฒ˜์Œ์— ์ข€ ํ—ค๋งค๊ณ  ์ดํ•ด๊ฐ€ ์•ˆ๋ผ์„œ ์ข€ ๋Š๋ ค์ง€๋Š” ํƒ“์— ์ž์ฑ…ํ–ˆ์—ˆ์ง€๋งŒ ๊ทธ๋Ÿด ๋•Œ๋งˆ๋‹ค
์šฐ๋ฆฌ ๋ฐฑ๋‘ฅ์ด ์ง€์˜๋‹˜๐Ÿงš๊ณผ ์ˆ˜๋นˆ๋‹˜๐Ÿงš์ด ๊ณ„์† ๊ฒฉ๋ คํ•ด์ฃผ๊ณ , ์šฐ๋ฆฌํŒ€ ์ •๋ง ์ž˜ ํ•˜๊ณ  ์žˆ๋‹ค๊ณ 
์„œ๋กœ์„œ๋กœ ๋งํ•ด์ฃผ์–ด์„œ ์—„์ฒญ๋‚œ ์œ„๋กœ๋ฅผ ๋ฐ›์•˜๋‹ค.

Django

Python

Bcrypt & JWT

Git & Github

AWS EC2 RDS



๊ธฐ๋Šฅ ๊ตฌํ˜„ ๐Ÿ’ป

๊ณตํ†ต ์‚ฌํ•ญ

  • ERD Modeling

User EndPoint

  • SignUp
  • SignIn
  • bcrypt
  • Jwt

Product EndPoint

  • Product List
  • Product Detail
  • Product List filtering

Order EndPoint

  • Cart Create
  • Cart List


๊ธฐ๋กํ•˜๊ณ  ์‹ถ์—ˆ๋˜ ์ฝ”๋“œ

# product.models
class Product(models.Model):
    name           = models.CharField( max_length=50)
    price          = models.DecimalField(max_digits=10, decimal_places=2)
    weight         = models.DecimalField(max_digits=5, decimal_places=2) 
    detail         = models.TextField()
    is_vegan       = models.BooleanField(default=False)
    is_new         = models.BooleanField(default=False)  
    is_soldout     = models.BooleanField(default=False)  
    sub_category   = models.ForeignKey('SubCategory', on_delete=models.CASCADE)
    label          = models.ManyToManyField('Label', through='ProductLabel')

    class Meta:
        db_table = "products"

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

class Label(models.Model):
    name    = models.CharField(max_length=50)
    
    class Meta:
        db_table ='labels'

class ProductLabel(models.Model):
    product = models.ForeignKey('Product', on_delete=models.CASCADE)
    label   = models.ForeignKey('Label', on_delete=models.CASCADE)

    class Meta:
        db_table='products_labels'

# Views
class ProductListView(View):
    def get(self, request):
        products = Product.objects.all()
            
        product_list = [{
            'product_id'    : product.id,
            'sub_category'  : product.sub_category.name,
            'name'          : product.name,
            'image_url'     : [image.image_url for image in product.image_set.all()],
            'price'         : product.price,
            'is_vegan'      : product.is_vegan,
            'is_new'        : product.is_new,
            'is_soldout'    : product.is_soldout,
            'product_label' : [label.label.name for label in product.productlabel_set.all()],
        } for product in products]
        return JsonResponse({'product_list_data': product_list}, status=200)

์ œ๋Œ€๋กœ ์ฒ˜์Œ ๊ตฌํ˜„ํ•ด๋ดค๋˜ List Comprehension๊ณผ
์–ด๋ ต๊ธฐ๋งŒ ํ–ˆ๋˜ '์—ญ์ฐธ์กฐ'.. ์‚ฌ์‹ค์ƒ ๋‚ด๊ฐ€ ์ œ์ผ ํ—ค๋งธ๋˜ ๊ตฌ๊ฐ„... ๐Ÿ˜ž
์—ญ์ฐธ์กฐ๋ฅผ ์ดํ•ดํ•˜๋ ค๊ณ  shell์„ ์—„์ฒญ๋‚˜๊ฒŒ ๊ดด๋กญํ˜”์—ˆ๋‹ค.
์‚ฌ์‹ค ์ง€๊ธˆ๋„ ์„ค๋ช…ํ•ด๋ณด๋ผ๊ณ  ํ•˜๋ฉด ์กฐ๊ธˆ ์–ด๋ฒ„๋ฒ„๋Œ€๊ณ 
100% ์ดํ•ดํ•œ๋‹ค๊ณ  ์žฅ๋‹ด ๋ชปํ•œ๋‹ค.
ํ•˜์ง€๋งŒ 2์ฐจ ํ”„๋กœ์ ํŠธ ๋•Œ์—๋„ shell์„ ๊ดด๋กญํž ์˜ˆ์ •์ด๊ณ ,
๊ฒฐ๊ตญ ๊ณ„์† ํ•˜๋‹ค๋ณด๋ฉด ์ดํ•ด๊ฐ€ ๋œ๋‹ค!
์•ˆ๋˜๋Š” ๊ฑด ์—†๋‹ค ์•ˆํ•˜๋Š” ๊ฒƒ๋ฟ

ํ˜‘์—…๊ณผ ์‚ฌ์šฉํ•œ Tools ๐Ÿ› 

๋งค์ผ ์•„์นจ 11์‹œ์— Front์™€ Back ํŒ€์›๋“ค์ด ๋ชจ์—ฌ Standup Meeting์„ ํ•˜์˜€๋‹ค.
์„œ๋กœ๊ฐ€ ๋งก์€ ๊ตฌํ˜„ ๊ธฐ๋Šฅ์˜ ์ง„ํ–‰ ์ƒํ™ฉ์„ ์˜๋…ผํ•˜๊ณ , ๋งก์€ ๊ธฐ๋Šฅ์˜ ์•ฑ์— ๋”ฐ๋ผ front์™€ back์˜
ํ†ต์‹ ์„ ๋งž์ถฐ๋ณด๊ธฐ๋„ ํ•˜์˜€๋‹ค. ์ฒ˜์Œ ๊ณ„ํšํ•  ๋•Œ์—” order, review๋“ฑ ํ•˜๊ณ ์‹ถ์€ ๊ธฐ๋Šฅ์ด ๋งŽ์•˜์ง€๋งŒ,
ํŒ€์› ๋ชจ๋‘์™€ ์˜๋…ผํ•œ ๊ฒฐ๊ณผ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋Š” front์™€ back์˜ ํ˜‘์—…์„ ๋ฐฐ์šฐ๋Š” ๊ณผ์ •์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์—ฌ
ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์ด๋ผ๋„ ์™„๋ฒฝํžˆ ๊ตฌํ˜„ํ•˜๊ณ , ๋‚จ์€ ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„์—๋Š” ์„œ๋ฒ„(AWS)์— ๋ฐฐํฌ ํ›„
์ตœ์ข…์ ์œผ๋กœ ๋งž์ถฐ๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ–๋Š” ๊ฑธ๋กœ ํ•˜์˜€๋‹ค.


Git & Github

git์˜ commit์„ ํ™•์ธํ•˜๋ฉฐ ์ž‘์—…์„ ํ•˜์˜€๊ณ , pushํ•  ๋•Œ์—” ๊ท€์—ฝ๊ฒŒ๋„ ๋‹ค๊ฐ™์ด ํ™•์ธํ•˜๋ฉฐ ํ•˜์˜€๋‹ค๐Ÿ’—
๊ทธ๋•Œ์—” ๋ฌด์„œ์› ๊ธฐ ๋•Œ๋ฌธ์—

Trello

Slack

์•„์‰ฌ์šด ์ 

์ดˆ๊ธฐ์— front์™€ back ์†Œํ†ต์˜ ๋ถ€์žฌ๋กœ ์ดˆ๊ธฐ ๋ฐฉํ–ฅ์„ ์ž˜๋ชป ์žก์•„ ์‹œ๊ฐ„์ด ๋งŽ์ด ์ง€์ฒด๋˜์—ˆ๋‹ค.
๋˜ ์†Œํ†ต์ด ์•ˆ๋ผ์„œ ์ƒ๊ฒผ๋˜ ๋ฌธ์ œ๋กœ๋Š” ์ง„ํ–‰ ์†๋„์˜ ์ฐจ์ด๊ฐ€ ์žˆ๋Š”๋ฐ,
back์—์„œ๋Š” order๋กœ์ง์„ ์งœ๊ณ  ์žˆ์—ˆ์ง€๋งŒ front์—์„œ๋Š” order ํŽ˜์ด์ง€๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ์— ์‹œ๊ฐ„์ด ์ด‰๋ฐ•ํ–ˆ๋˜ ๊ฒƒ.

์ž˜ํ•œ ์ 

๋‚จ์€ ์‹œ๊ฐ„์— ์„œ๋กœ์˜ ์ง„ํ–‰ ์†๋„๋ฅผ ๋ฐฐ๋ คํ•˜๊ณ  ํŒ€์›๊ณผ์˜ ์†Œํ†ต,
back๊ณผ front์˜ ์†Œํ†ต ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋Š” ๊ฒƒ์— ํ”„๋กœ์ ํŠธ ๋ฐฉํ–ฅ์„ ๋ฐ”๊พธ์–ด
1์ฐจ ํ”„๋กœ์ ํŠธ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๋ ๋งˆ์ณค๋‹ค.๐Ÿ’—

Klush-Backend-Presentation
๊ธฐ์Šน์ „๊ฒฐ ๋šœ๋ ทํ•œ ์šฐ๋ฆฌ klushํŒ€์› ์—ฌ๋Ÿฌ๋ถ„ ์‚ฌ๋ž‘ํ•จ๋‹ค๐ŸŒธ

profile
Backend Developer

7๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2021๋…„ 3์›” 28์ผ

์ธ์•„๋‹˜ 1์ฐจ ํ”Œ์  ์–ด๋ ค์›€ ๋งŽ์œผ์…จ์„ํ…๋ฐ
์ˆ˜๊ณ  ๋งŽ์œผ์…จ์Šต๋‹ˆ๋‹ค ๐ŸŽ‰๐ŸŽ‰

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 3์›” 28์ผ

๋„ˆ๋ฌด ์ž˜ ํ–ˆ์Šต๋‹ˆ๋‹ค~! ์ธ์•„๋‹˜~!!!!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 3์›” 29์ผ

์—ญ์‰ฌ ์ธ์•„๋‹˜์€ ์žฅ๊ณ  ์˜์žฌ์˜€์ˆด! ํ”„๋กœ์ ํŠธ ์ˆ˜๊ณ ํ–ˆ๋Ÿฌ์‰ฌ~~~

1๊ฐœ์˜ ๋‹ต๊ธ€