1. shop 앱 만들기
2. shop > models.py
from django.db import models
from django.urls import reverse
# 카테고리 모델
class Category(models.Model):
# 카테고리 이름 결정, db_index를 true로 설정하면 카테고리 정보 저장 테이블은 이 이름 열을 인덱스로 설정
name = models.CharField(max_length=200, db_index=True)
# SEO(search engine optimization) => 요즘은 OG(open graph)도 넣음
meta_description = models.TextField(blank=True)
# 카테고리와 상품 모두에 설정, 상품명을 이용해서 url 만들기
# allow_unicode는 영문 외 모든 언어 사용 가능
slug = models.SlugField(max_length=200, db_index=True, unique=True, allow_unicode=True)
# 관리자 페이지에서 보여지는 객체가 단수일 때, 복수일 때 표현하는 값 결정
class Meta:
ordering = ['name']
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('shop:product_in_category', args=[self.slug])
# 상품 모델
class Product(models.Model):
# 상품 모델은 foreignkey 필드를 이용해서 카테고리 모델과 관계 설정
# 카테고리를 삭제해도 상품은 남아있어야 하니 on_delete를 set_null로 설정
# null 값 저장 가능하기 위해 null = true로 설정
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='products')
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True, allow_unicode=True)
image = models.ImageField(upload_to='products/%Y/%m/%d',blank=True)
description = models.TextField(blank=True)
meta_description = models.TextField(blank=True)
# price: 제품 가격, stock: 재고
price = models.DecimalField(max_digits=10,decimal_places=2)
stock = models.PositiveIntegerField()
# available_display: 상품 노출 여부, available_order: 상품 주문 가능 여부
available_display = models.BooleanField('Display', default=True)
available_order = models.BooleanField('Order', default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
# index_together은 멀티 컬럼 색인 기능으로 id와 slug 필드를 묶음
class Meta:
ordering = ['-created']
index_together = [['id','slug']]
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('shop:product_detail', args=[self.id, self.slug])
3. makemigrations와 migrate로 데이터베이스에 반영하기
4. 이제 view를 만들어보자
from django.shortcuts import render, get_object_or_404
from .models import *
# get_object_or_404는 찾는 객체가 없을 경우 자동으로 404를 보여줌
# 카테고리 페이지
def product_in_category(request, category_slug=None):
current_category = None
categories = Category.objects.all()
products = Product.objects.filter(available_display=True)
# url로부터 category_slug를 찾아서 현재 어느 카테고리를 보여주는 것인지 판단
# 선택한 카테고리가 없으면 전체 상품 목록 노출
if category_slug:
current_category = get_object_or_404(Category, slug=category_slug)
products = products.filter(category=current_category)
# filter 메서드는 여러번 쓰이지만, 실제 DB에는 단 한번 전달 (Lazy evalutation 사용하기 때문)
return render(request, 'shop/list.html',
{'current_category': current_category, 'categories': categories, 'products': products})
# 제품 상세 뷰
# URL에서 slug 값을 읽어와서 해당 제품을 찾고 노출
def product_detail(request, id, product_slug=None):
product = get_object_or_404(Product, id=id, slug=product_slug)
return render(request, 'shop/detail.html', {'product': product})
5. URL 연결
- 만든 뷰를 동작시키려면 urls.py에서 URL을 연결해 줘야 함
- shop 폴더에 urls.py 생성
from django.urls import path
from .views import *
app_name = 'shop'
urlpatterns = [
# 전체 제품 노출
path('', product_in_category, name='product_all'),
# 카테고리 선택이 있는 경우
path('<slug:category_slug>/', product_in_category, name='product_in_category'),
# 제품 상세
path('<int:id>/<product_slug>/', product_detail, name='product_detail'),
]
6. 템플릿 만들기
templates > base.html에 만들기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<!-- jquery slim 지우고 minified 추가 -->
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
{% block script %}
{% endblock %}
{% block style %}
{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">Django Shop</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarSupportedContent">
<ul class="navbar-nav justify-content-end">
<li class="nav-item">
{% if user.is_authenticated %}
<a class="nav-link" href="{% url 'account_logout' %}">Logout</a>
{% else %}
<a class="nav-link" href="{% url 'account_login' %}">Login</a>
{% endif %}
</li>
<li class="nav-item ">
<a class="nav-link btn btn-outline-success" href="{% url 'cart:detail' %}">Cart
{% if cart|length > 0 %}
${{ cart.get_total_price }} with {{cart|length}} items
{% else %}
: Empty
{% endif %}
</a>
</li>
</ul>
</div>
</nav>
<div class="container">
{% block content %}
{% endblock %}
</div>
</body>
</html>
{% extends 'base.html' %} {% block title %}Category Page{% endblock %} {% block content %}
All
{% for c in categories %}
{{c.name}}
{% endfor %}
{% if current_category %}{{current_category.name}}{% else %}All Products{% endif %}
{% for product in products %}
{% endfor %}
{% extends 'base.html' %} {% block title %}Product Detail{% endblock %} {% block content %}
{{product.name}}
Price {{product.price}}
Description{{product.description|linebreaks}}
7. 서버 실행
python manage.py runserver
8. 관리자 페이지 등록
from django.contrib import admin
from .models import *
# 카테고리와 제품 모두 등록해서 관리하겠다
class CategoryAdmin(admin.ModelAdmin):
list_display = ['name','slug']
prepopulated_fields = {'slug':('name',)}
admin.site.register(Category, CategoryAdmin)
class ProductAdmin(admin.ModelAdmin):
list_display = ['name','slug','category','price','stock','available_display','available_order','created','updated']
list_filter = ['available_display','created','updated','category']
prepopulated_fields = {'slug': ('name',)}
list_editable = ['price','stock','available_display','available_order']
admin.site.register(Product, ProductAdmin)
9. 소셜 로그인 추가
- pip install django-allauth
'Django' 카테고리의 다른 글
Getting Started with Amazon Personalize (0) | 2023.03.20 |
---|---|
REST API 구축 (0) | 2023.03.14 |
쇼핑몰 만들기 프로젝트 - aws 설정 (0) | 2023.03.13 |
장고를 시작하며 (0) | 2023.03.13 |
python2 vs python3 (0) | 2023.02.25 |