3 분 소요

상품에 맞는 모델을 어떻게 만들까?

Products 모델 만들기

models.py

from django.db import models
from category.models import Category
from django.utils.text import slugify

# Create your models here.

class Product(models.Model):
    product_name    = models.CharField(max_length=200, unique=True)
    slug            = models.SlugField(max_length=200, unique=True, allow_unicode=True)
    description     = models.TextField(max_length=500, blank=True)
    price           = models.IntegerField()
    images          = models.ImageField(upload_to='photos/products')
    stock           = models.IntegerField()
    is_available    = models.BooleanField(default=True)
    category        = models.ForeignKey(Category, on_delete=models.CASCADE)
    created_date    = models.DateTimeField(auto_now_add=True)
    modified_date   = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.product_name

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        self.slug = slugify(self.product_name, allow_unicode=True)
        super().save(force_insert, force_update, using, update_fields)
  • slug 자동완성 기능을 쓰려면 파라미터에 allow_unicode=True 로 해둬도 가능하지만 그럴 경우 urls 에서 다시 한 번 작업해줘야 한다.
    • model 의 save함수를 오버라이딩하면 모델에서 저장될 때마다 slug fields 값을 추가하도록 할 수 있다.
  • images ->카테고리 모델에서 이미지필드의 upload 장소를 베이스를 photos 로 해주었으니 동일하게 맞춰준다.

admin.py

from django.contrib import admin
from .models import Product

# Register your models here.

class ProductAdmin(admin.ModelAdmin):
    list_display = ('product_name', 'price', 'stock', 'category', 'modified_date', 'is_available')
    prepopulated_fields = {'slug': ('product_name',)}

admin.site.register(Product, ProductAdmin)

렌더링해주기

  • 이제 커스텀한 모델을 html에 반복문으로 보내주면 끝이다.
from django.shortcuts import render
from store.models import Product

def home(request):
    products = Product.objects.all().filter(is_available = True)
    context = {
        'products': products,
    }
    return render(request, 'home.html',context)
<div class="row">
    {% for product in products %}
    <div class="col-md-3">
        <div class="card card-product-grid">
            <a href="./product-detail.html" class="img-wrap"> <img src="{{product.images.url}}"> </a>
            <figcaption class="info-wrap">
                <a href="./product-detail.html" class="title">{{ product.product_name }}</a>
                <div class="price mt-1">{{ product.price }}</div> <!-- price-wrap.// -->
            </figcaption>
        </div>
    </div>
    {% endfor %}
</div> <!-- row.// -->

숫자 포맷 적용시키기

  • 장고에는 숫자나 날씨 포맷이 이미 내장되어있다.

settings.py

INSTALLED_APPS = [
    'django.contrib.humanize', # 숫자 포멧
]
  • 따로 라이브러리 설치 필요 없이 그냥 humanize 를 앱에 등록해준다.
{% load humanize %}

{{ product.price|intcomma}}
  • 그 후 static 폴더처럼 호출한 뒤 태그를 씌워주면 적용된다.
  • [참고]([django.contrib.humanize Django documentation Django (djangoproject.com)](https://docs.djangoproject.com/en/4.2/ref/contrib/humanize/))

페이지 연결시키기

  • 메인화면이 아닌 store 페이지를 따로 만들고 거기서 카테고리 별로 나눈 페이지를 만들려고 했는데 그 이유는 페북이나 구글 스크립트를 심어 놨을 때 세분화 할 수록 추적할 때도 좋고 인사이트를 얻기도 좋다
  • 두 번째로는 사용자가 원하는 상품을 찾기 쉽게 하기 위해서다.

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.store, name='store'),
]

views.py

from .models import Product

def store(request):
    products = Product.objects.all().filter(is_available = True)
    product_count = products.count()
    context = {
        'products': products,
        'product_count' : product_count,
    }
    return render(request, 'store/store.html',context)
  • 모델 Product에 있는 모든 객체들을 갖고 온 후 객체 products에 담아둔다.
  • .count() 함수를 써서 총 몇 개인지 알 수 있는 객체를 만들고 context로 보내준다.
  • html 은 이전과 동일하게 반복문으로 돌려준다.

카테고리 별로 페이지 출력하게 만들기 (slug)

  • 왼쪽에 카테고리들은 현재 데모로 구현되어있다. 이 카테고리들 중 하나를 클릭하면 해당 카테고리에 맞는 아이템들만 반복문으로 출력하게 만들고 싶었다.
    • 이를 구현하기 위해서 slug를 사용하면 편하다.

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.store, name='store'),
    path('<slug:category_slug>/', views.store, name='products_by_category'),
]
  • /store/slug의 형태로 주소를 받는다.
  • slug 주소를 views에서 받은 후 유효성 검사를 진행한다.

views.py

from django.shortcuts import render, get_object_or_404
from .models import Product, Category

# Create your views here.
def store(request, category_slug=None):
    categories = None
    products = None

    if category_slug != None:
        categories = get_object_or_404(Category, slug=category_slug)
        products = Product.objects.filter(category=categories, is_available=True)
        product_count = products.count()

    else:
        products = Product.objects.all().filter(is_available=True)
        product_count = products.count()
        
    context = {
        'products': products,
        'product_count': product_count,
    }
    return render(request, 'store/store.html', context)
  • 우선 처음에 파라미터 category_slug 값이 없을 수도 있으니 argument 값으로 None을 주는게 좋다.
  • 이렇게 하면 슬러그 주소가 없을 경우 기존에 랜더링 했던 것과 동일하게 출력을 한다.
  • 만약 매개변수 값이 있다면 get_object_or_404 를 통해 Category 에서 슬러그 주소와 일치하는 값이 있다면 객체 categories로 보내고 없으면 404 오류를 만든다.
  • categories 값이 만들어 졌다면 필터를 거쳐 products 객체를 만든후 context로 보내주면 된다.

댓글남기기