STEP 1 shop app 생성
python manage.py startapp shop
STEP 2 settings.py INSTALLED_APP
에 shop 등록
INSTALLED_APPS = [
'shop',
]
STEP 1 shop app
에 model 등록
from django.db import models
from django.urls import reverse
# Create your models here.
# 카테고리 모델
class Category(models.Model):
name = models.CharField(max_length=30, db_index=True)
meta_description = models.TextField(blank=True)
slug = models.SlugField(max_length=200, db_index=True, allow_unicode=True) // 상품명 등을 이용해서 url을 만드는 방식
class Meta: // 관리자 페이지에서 보여질 객체의 단복수 유무에 따라 나눔
ordering=['name']
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self): // 원하는 모델을 찾을 수 있는 url
return reverse('shop:product_in_category', args=[str(self.slug)])
# 상품 모델
class Product(models.Model): // 카테고리와 외래키 관계 ( 카테고리를 삭제해도 상품은 삭제되지 않도록 함 )
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='products')
name = models.CharField(max_length=100, db_index=True)
slug = models.SlugField(max_length=100, db_index=True, unique=True, allow_unicode=True)
image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True)
baeminImage = models.ImageField(upload_to='productsQR/%Y/%m/%d', blank=True)
description = models.TextField(blank=True)
meta_description = models.TextField(blank=True)
url = models.URLField(default='정보없음')
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField()
## 상품 홍보를 목적으로 재고가 없는 상품을 노출하는 경우도 있으므로 변수를 나눠서 관리
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)
class Meta:
ordering = ['-created']
index_together = [['id', 'slug']] // id + slug 묶어서 탐색이 가능하도록 설정
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('shop:product_detail', args=[self.id, self.slug])
STEP 2 migration DB에 반영
python manage.py makemigrations shop
python manage.py migrate shop
STEP 1 카테고리 페이지 뷰 작성
from django.shortcuts import render, get_object_or_404
from .models import*
# Create your views here.
def product_in_category(request, category_slug=None):
current_category = None
categories = Category.objects.all() // 관리자 페이지에서 등록된 카테고리 객체들을 categories 변수에 저장
products = Product.objects.filter(available_display=True) // 관리자 페이지에서 등록된 상품 객체들 중 노출 여부가 가능한 객체만 products 변수에 저장
if category_slug: // category_slug를 찾아 현재 어느 카테고리를 보여주는지 판단
current_category = get_object_or_404(Category, slug = category_slug)
products = products.filter(category =current_category)
return render(request,'shop/list.html',{'current_category':current_category,'categories':categories,'products':products})
STEP 2 상품 상세 페이지 뷰 작성
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} )
URL로부터 slug 값 읽어오고 해당 상품을 찾아 그 상품을 노출하는 방식
STEP 3 shop URL 작성
// shop/urls.py
from django.urls import path
from .views import *
app_name='shop'
urlpatterns=[
path('',product_in_category, name='product_all'),
path('<category_slug>/',product_in_category, name='product_in_category'),
path('<int:id>/<product_slug>/',product_detail,name='product_detail'),
]
// config/urls.py 의 urlpatterns에 적어주는 것
path('',include('shop.urls')),
중복되는 템플릿이 있을 때 기준이 되는 템플릿을 만들고 이를 확장하는 형식
ex ) 어느 페이지를 가던 메뉴바가 보이므로 기준 템플릿에서 이를 미리 작성할 것
STEP 1 프로젝트 루트에 templates 폴더 생성 > base.html 생성
부트스트랩 사용 > slim 버전 말고 minified 버전 사용
: slim 버전은 ajax 기능이 없어서 쇼핑몰에 부적합
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>onlineShop</title>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<!-- jQuery minified 버전-->
<script src="https://code.jquery.com/jquery-3.6.4.min.js"
integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
{% block script %}
{% endblock %}
{% block style %}
{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="/">香</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">
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link btn btn-outline-info" href="{% url 'account_logout' %}">로그아웃</a>
{% else %}
<a class="nav-link btn btn-outline-info" href="{% url 'account_login' %}">로그인</a>
{% endif %}
</li>
<li class="nav-item">
<a class="nav-link btn btn-outline-info" href="">장바구니
{% if cart|length > 0 %}
<span class="badge badge-pill badge-primary">{{cart|length}}</span>
{% else %}
: 비어있음
{% endif %}
</a>
</li>
</ul>
<button class="btn btn-outline-info my-2 my-sm-0" type="submit">검색</button>
</div>
</nav>
<div class="container">
{% block content %}
{% endblock %}
</div>
</body>
</html>
STEP 2 config/settings.py 의 TEMPLATES 부분 수정
'DIRS': [os.path.join(BASE_DIR,'templates'),
// 템플릿을 확장할 때 base.html을 찾을 수 있도록 미리 경로 설정
STEP 3 shop/templates/shop/list.html 생성
{% extends 'base.html' %} // base.html 확장
{% block title %}Category Page{% endblock %}
{% block content %}
<br>
<div class="row">
<div class="col-2"> <!--col-2 : 2조각-->
<div class="list-group">
<a href="/" class="list-group-item list-group-item-action list-group-item-secondary
{% if not current_category%}active{% endif %}">All</a>
{%for c in categories %}
<a href="{{c.get_absolute_url}}" class="list-group-item list-group-item-action list-group-item-secondary
{% if current_category.slug == c.slug %}active{% endif %}">
{{c.name}}</a>
{% endfor %}
</div>
</div>
<div class="col">
<div class="alert alert-danger" role="alert">
{% if current_category %}{{current_category.name}}를/을 판매하고 있는 스토어입니다.
{% else %} 모든 스토어 {% endif %}
</div>
<div class="row">
{% for product in products %}
<div class="col-sm-4">
<div class="card">
<img class="card-img-top" src="{{product.image.url}}" alt="Product image" width="466px" height="270">
<div class="card-body" style="text-align:center">
<h5 class="card-title">{{product.name}}</h5>
{% load humanize %}
<img class="card-img" src="{{product.baeminImage.url}}" alt="QRcode image" style="width:70px; height:70px; text-align:center;"><p/>
<h4 class="badge badge-light">
₩{{product.price | floatformat:'0' | intcomma}}</h4><p/>
<a href="{{product.get_absolute_url}}" class="btn btn-outline-info">View Detail</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
STEP 4 config/settings.py에 app 등록
{% load humanize %} // humanize에서 제공하는 필터 사용
INSTALLED_APPS =[
'shop',
'django.contrib.humanize',
]
STEP 5 shop/templates/shop/detail.html 생성
{% extends 'base.html' %}
{% block title %}Product Detail{% endblock %}
{% block content %}
<br>
<div class="container">
<div class="row">
<div class="col-4">
<img src="{{product.image.url}}" width="300px" height="300px">
</div>
<div class="col">
<h2 class="display-6">{{product.name}}</h2>
<p><span class="badge badge-light">가격</span>
{% load humanize %}
₩{{product.price | floatformat:'0' | intcomma}}</p>
<form action="{% url 'cart:product_add' product.id %}" method="post">
{{add_to_cart}}
{% csrf_token %}
<input type="submit" class="btn btn-outline-info btn-sm" value="장바구니에 담기">
</form>
<br>
<h5><span class="badge badge-light"><a href="{{product.url}}">홈페이지 바로가기</a></span></h5>
<br>
<h5><span class="badge badge-secondary">설명</span>{{product.description|linebreaks}}</h5>
</div>
</div>
<br><br>
{% load disqus_tags %}
{% disqus_show_comments %}
</div>
{% endblock %}
STEP 6 shop/admin.py
# category option
from django.contrib import admin
from .models import *
# Register your models here.
class CategoryAdmin(admin.ModelAdmin):
list_display=['name','slug']
prepopulated_fields = {'slug':('name',)} // slug 필드는 name 필드 값에 따라 자동으로 설정
admin.site.register(Category,CategoryAdmin)
# shop app
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)
- prepopulated_fields : slug 필드는 name 필드 값에 따라 자동으로 설정됨
- list_editable : 목록에서도 주요 값들을 바로바로 변경할 수 있게 설정
STEP 7 관리자 페이지에서 상품 등록
python manage.py runserver
STEP 1 django_allauth 다운로드
// 회원가입을 편리하게 해주는 장고의 기능
소셜 로그인 > 기존에 있는 유명한 앱을 다운로드 해서 사용
pip install django_allauth
STEP 2 INSTALLED_APPS 에 등록
'django.contrib.sites', // 사이트 설정을 위한 것
'allauth', // allauth와 관련해 필요한 앱 등록
'allauth.account', // 가입한 계정 관리
'allauth.socialaccount', // 소셜 계정으로 가입한 계정 관리
'allauth.socialaccount.providers.naver',
STEP 3 config/settings.py 에 설정 추가
AUTHENTICATION_BAKENDS = (
'django.contrib.auth.backends.ModelBackend', // 관리자 페이지 등에 사용자명으로 로그인 하기 위해 장고 기본 ModelBackend 추가
'allauth.account.auth_backends.AuthenticationBackend', // alluath 방식 추가하기 위해 AuthenticationBackend 추가
)
SITE_ID = 1 // 여러 사이트를 운영할 때 각각의 사이트의 ID
LOGIN_REDIRECT_URL = '/' // 로그인 후 이동할 페이지 = 메인 페이지
STEP 4 config/urls.py에 경로 추가
path('accounts/',include('allauth.urls')),
STEP 5 allauth
DB에 반영
python manage.py migrate
STEP 1 애플리케이션 등록
STEP 2 django-admin에 client ID / Secret 등록
STEP 2 INSTALLED_APPS 에 등록
'allauth.socialaccount.providers.naver',
STEP 1 내 애플리케이션 > 애플리케이션 추가하기
STEP 2 엡 설정 > 플랫폼
STEP 3 제품 설정 > 카카오 로그인
STEP 4 제품 설정 > 카카오 로그인 > 동의항목
STEP 5 앱 키 발급
STEP 2 django-admin에 REST API
> client ID / Admin
> Secret 등록
STEP 5 INSTALLED_APPS 에 등록
'allauth.socialaccount.providers.kakao',
두 개의 social accounts
가 정상적으로 생성된 것
기존에 학습 해왔던 방식을 토대로 틀을 작성하되 로그인 기능까지 넣어 구현하는 것을 배우고 익히는 것에 집중하여 스터디 진행