[0611] timeattack_retry

nikevapormax·2022년 6월 11일
0

TIL

목록 보기
46/116

🙍‍♂️ Time Attack Retry

🙎‍♂️ 프로젝트 생성

  • 이제 익숙해질만도 한 프로젝트 생성!
  • 프로젝트를 담을 폴더 timeattack_0610을 내 로컬에 생성해준다.
  • pyCharm 또는 VS Code를 키고 내가 생성한 timeattack_0610를 연다.
  • timeattack_0610 폴더를 열게 되면 아~~무 것도 없다.(넣은게 없으니까!)
  • 이제 프로젝트를 생성하면 되는데, 선행되어야 할 부분이 있다. 바로 가상환경 세팅이다. 나는 여러 프로젝트 및 개인 연습을 진행하면서 conda에 만들어 놓은 가상환경을 쓰도록 하겠다. (과로사해도 할 말이 없다)
  • 가상환경까지 세팅이 되었으니 아래 명령어를 terminal에 입력하면 알아서 프로젝트가 생성된다.
$ django-admin startproject timeattack_0610 .

🙎‍♂️ app 생성

  • 프로젝트를 진행할 때 필요한 app들을 생성해보자.
  • 일단 userproduct app을 생성할 것이다.
  • app 생성도 project 생성과 매한가지다.
$ django-admin startapp user
$ django-admin startapp product
  • app을 생성하면 뭘 해야 한다고???
  • timeattack_0610/settings.py에다가 알려줘야 합니다!
#### 상단 생략 ####

INSTALLED_APPS = [
    'product',
    'user',

    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

#### 하단 생략 ####

🙎‍♂️ app 별 model 생성

  • 나는 지금까지 나의 편안함을 추구하느라 CharField를 주로 사용해 왔다. SQLD까지 딴 사람이 너무 안일했다 생각하며 반성한다. 이번 프로젝트는 다른 것을 다 떠나 model을 짜는 연습을 더 하고 싶다 생각했기 때문에 좀 더 심혈을 기울여 궁금한게 나오면 바로 찾아보았다.
  • 먼저 user app의 model을 생성해보자.

- user app

  • user app에는 사용자의 정보를 담을User 모델이 있어야 된다.
  • user/models.py
from django.db import models

# Create your models here.
class User(models.Model):
    class Meta:
        db_table = 'user'

    email = models.EmailField(max_length=100, null=False, unique=True)
    password = models.CharField(max_length=100)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
  • 자 여기서 궁금증이 생겼다. 도대체 auto_now_addauto_now는 뭔 차이냐?? add가 없다는 것으로 추론이 되지 않았다. 그래서 아래의 블로그를 참조해 답을 얻었다.

    auto_now_add vs. auto_now

    • auto_now_add : model 이 최초 저장(insert) 시에만 현재날짜(date.today())를 적용

    • auto_now : model이 save 될 때마다 현재날짜(date.today())로 갱신

  • 뜻을 보니 이해가 갔다. 계정이 언제 생성되었는지에 대한 정보와 계정에 언제 변화가 있었는지에 대한 정보를 제공하기 위함인 것 같다.

  • model을 생성했으니 admin 페이지에서 사용할 수 있도록 등록해보자.

from django.contrib import admin
from .models import User

# Register your models here.
admin.site.register(User)

- product app

  • 우리는 product model과 category model을 만들어야 한다. 그런데 이때 productcategory의 내용을 ForeignKey를 통해 받아 사용해야 한다. 그러므로 나는 category를 먼저 만들도록 하겠다.
  • product/models.py
from django.db import models

# Create your models here.
class Category(models.Model):
    class Meta:
        db_table = 'category'

    name = models.CharField(max_length=100)


class product(models.Model):
    class Meta:
        db_table = 'product'

    name = models.CharField(max_length=100)
    # Category 모델이 사라져도 해당 부분은 사라지면 안되니까 models.SET_NULL로 설정
    # null=True : 필드의 값이 null로 저장되는 것을 허용 (기본값 : False)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    # blank=True : 필드가 폼(입력 양식)에서 빈 채로 저장되는 것을 허용 (기본값 : False)
    # null=True와 blank=True를 모두 설정하면 어떤 조건으로든 빈 값 가능 (CharField와 TextField 제외)
    image = models.ImageField(upload_to='product/%Y/%m/%d', blank=True)
    desc = models.TextField(blank=True)
    # 10 자리의 숫자 중 2자리까지의 소숫점 이하 허용
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.IntegerField()

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    # 쿼리셋으로 object를 불러올 때 모든 내용이 나오지 않고 name으로 나오게 해줌 (ex. <Queryset: apple macbook>)
    def __str__(self):
        return self.name
  • django model의 ForeignKey의 on_delete 종류
    • CASCADE : ForeignKeyField를 포함하는 모델 인스턴스(row)도 같이 삭제
    • PROTECT : 해당 요소가 같이 삭제되지 않도록 ProtectedError를 발생
    • SET_NULL : ForeignKeyField 값을 NULL로 바꿈 (null=True일 때만 사용)
    • SET_DEFAULT : ForeignKeyField 값을 default 값으로 변경 (default 값이 있을 때만 사용)
    • SET(함수) : ForeignKeyField 값을 SET에 설정된 함수 등에 의해 설정
    • DO_NOTHING : 아무런 행동을 취하지 않음 (참조 무결성을 해칠 수 있음)
  • ImageField 관련 자료

    django 공홈, upload_to 설정


  • OrderStatus model 생성
    • 주문 진행 상태에 대한 내용을 담는다.
    • 처음에 이 모델의 요소를 다 만들었는데 알고 보니 admin 페이지에서 내용을 추가했다. 그래서 이번에는 비워두었다.
class OrderStatus(models.Model):
    class Meta:
        db_table = 'order_status'
  • ProductOrder model 생성
    • 우리는 이미 Product model을 만들어 놓았다. 그렇다면 유저가 주문한 상품의 개수를 저장하는 해당 모델은 ProductForeignKey로 받아와 사용하면 될 것 같다.
    • 하나의 주문에 포함되는 상품의 개수는 여러 개가 될 수 있지만, 상품의 개수는 그것이 해당하는 하나의 주문에 귀속되어야 한다. 따라서 일대다 관계라 생각한다.
    • 그리고 어떤 유저가 주문했는지에 대해서도 표시해주어야 하기 때문에 아래와 같이 작성했다.
class ProductOrder(models.Model):
    class Meta:
        db_table = 'product_order'
        
	# null=True와 blank=True를 모두 설정하면 어떤 조건으로든 빈 값 가능 (CharField와 TextField 제외)
    product = models.ForeignKey(Product, on_delete=models.SET_NULL, blank=True, null=True)
    product_cnt = models.IntegerField()
    user_order = models.ForeignKey('UserOrder', on_delete=models.SET_NULL, blank=True, null=True)
  • UserOrder model 생성
    • 바로 위의 모델에서 외래키로 가져오려는 모델이다. 해당 모델에는 유저의 주문 정보가 담기게 된다.
    • User 모델에서 사용자의 정보를 받아와야 하며, 하나의 유저에 여러 주문이 있을 수 있지만 한 주문에 여러 명의 유저가 있으면 안되기에 일대다로 설정하였다.
    • OrderStatus 모델에서 정보를 받아와 사용자의 주문이 어떻게 진행되고 있는지 보면 좋겠다고 생각해 추가하였다. 하나의 주문에 여러 개의 진행 상태가 있을 수 있다 생각했다. 왜냐면 실생활에서도 한 번에 주문한다 해서 꼭 다 같이 오는 것은 아니기 때문이다. 하지만 하나의 주문 상태에는 하나의 유저만이 링크되어야 한다고 생각해 일대다로 설정했다.
    • 그리고 어떤 물건을 시켰는지에 대한 정보도 필요할 것 같다. 그래서 ProductOrder에서 정보를 받아오도록 설정했다.
    • 이렇게 모델을 설정하다보니 하나정도의 모델은 줄일 수 있을 것 같다고 생각은 했다. 물론 내용이 복잡해질 수 있어 나누어진 것 같지만 UserOrderProductOrder는 하나로 합쳐져도 좋을 것 같다 생각했다. (다음에 시도해보자!)
class UserOrder(models.Model):
    class Meta:
        db_table = 'user_order'

    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    order_status = models.ForeignKey(OrderStatus, on_delete=models.SET_NULL, null=True)
    product_order = models.ForeignKey(ProductOrder, on_delete=models.SET_NULL, null=True)

    delivery_address = models.CharField(max_length=1000)
    order_time = models.DateTimeField()
    total_price = models.DecimalField(max_digits=20, decimal_places=2)
    discount = models.DecimalField(max_digits=20, decimal_places=2)
    final_price = models.DecimalField(max_digits=20, decimal_places=2)
    active = models.BooleanField()
  • 만든 모델들을 product/admin.py에 등록하도록 하겠다.
from django.contrib import admin
from . import models

# Register your models here.
admin.site.register(models.Category)
admin.site.register(models.Product)
admin.site.register(models.ProductOrder)
admin.site.register(models.UserOrder)
admin.site.register(models.OrderStatus)
  • 좀 더 유연한 url의 사용을 위해 get_absolute_url()을 사용할 수 있다. 해당 부분을 포함한 전체 코드는 다음과 같다.
from django.db import models
from django.urls import reverse
from user.models import User


# Create your models here.
class Category(models.Model):
    class Meta:
        db_table = 'category'

    name = models.CharField(max_length=100)

    def get_absolute_url(self):
        print("get_url = ", end=""), print(reverse('product:list', args=[self.name]))
        return reverse('product:list', args=[self.name])  # product/list/laptop


class Product(models.Model):
    class Meta:
        db_table = 'product'

    name = models.CharField(max_length=100)
    # Category 모델이 사라져도 해당 부분은 사라지면 안되니까 models.SET_NULL로 설정
    # null=True : 필드의 값이 null로 저장되는 것을 허용 (기본값 : False)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    # blank=True : 필드가 폼(입력 양식)에서 빈 채로 저장되는 것을 허용 (기본값 : False)
    # null=True와 blank=True를 모두 설정하면 어떤 조건으로든 빈 값 가능 (CharField와 TextField 제외)
    image = models.ImageField(upload_to='product/%Y/%m/%d', blank=True)
    desc = models.TextField(blank=True)
    # 10 자리의 숫자 중 2자리까지의 소숫점 이하 허용
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.IntegerField()

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    # 쿼리셋으로 object를 불러올 때 모든 내용이 나오지 않고 name으로 나오게 해줌 (ex. <Queryset: apple macbook>)
    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('product:product_detail', args=[self.id, self.name])


class OrderStatus(models.Model):
    class Meta:
        db_table = 'order_status'


class ProductOrder(models.Model):
    class Meta:
        db_table = 'product_order'

    # null=True와 blank=True를 모두 설정하면 어떤 조건으로든 빈 값 가능 (CharField와 TextField 제외)
    product = models.ForeignKey(Product, on_delete=models.SET_NULL, blank=True, null=True)
    product_cnt = models.IntegerField()
    user_order = models.ForeignKey('UserOrder', on_delete=models.SET_NULL, blank=True, null=True)


class UserOrder(models.Model):
    class Meta:
        db_table = 'user_order'

    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    order_status = models.ForeignKey(OrderStatus, on_delete=models.SET_NULL, null=True)
    product_order = models.ForeignKey(ProductOrder, on_delete=models.SET_NULL, null=True)

    delivery_address = models.CharField(max_length=1000)
    order_time = models.DateTimeField()
    total_price = models.DecimalField(max_digits=20, decimal_places=2)
    discount = models.DecimalField(max_digits=20, decimal_places=2)
    final_price = models.DecimalField(max_digits=20, decimal_places=2)
    active = models.BooleanField()
profile
https://github.com/nikevapormax

0개의 댓글