EC site

基本設定

cd pj

pj/pj/settings.py

pj/pj/urls.py

appアプリ

app/urls.py

app/views.py

app/forms.py

app/models.py

app/views.py

app/admin.py

userアプリ

テンプレートファイル

基本設定

cd pj
django-admin startproject pjpython manage.py startapp userspython maange.py startapp apppip install Pillow

カスタムユーザーモデル関連のファイルのみusersアプリに入れる

pj/pj/settings.py
import osINSTALLED_APPS = [ ‘users’,      ‘app’,      ‘django.contrib.humanize’,      ‘django.contrib.sessions’,②]MIDDLEWARE = [ ‘django.contrib.sessions.middleware.SessionMiddleware’, ]②
STATIC_URL = ‘/static/’STATICFILES_DIRS = ( os.path.join(BASE_DIR, ‘static’), )
MEDIA_URL = ‘/media/’MEDIA_ROOT = os.path.join(BASE_DIR, ‘media’)
AUTH_USER_MODEL = ‘users.User’①
LOGIN_URL = ‘app:login’LOGIN_REDIRECT_URL = ‘app:index’LOGOUT_REDIRECT_URL = ‘app:index’

SESSION_SAVE_EVERY_REQUEST = True③

①usersアプリのmodels.pyで定義したUserモデルをカスタムユーザーモデルとして利用

②session情報をデータベースに保存

③sessionの更新を反映させる

pj/pj/urls.py
from django.contrib import adminfrom django.urls import path, includefrom django.conf import settingsfrom django.conf.urls.static import staticurlpatterns = [ path(‘admin/’, admin.site.urls), path(‘’, include(‘app.urls’)),]urlpatterns += static(     settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

appアプリ

app/urls.py
from django.urls import pathfrom django.contrib.auth import views as auth_viewsfrom . import viewsurlpatterns = [ path(‘’, views.index, name=’index’), path(‘login’, auth_views.LoginView.as_view(template_name=’app/login.html’), name=’login’), path(‘logout’, auth_views.LogoutView.as_view(), name=’logout’),     path(‘signup’, views.signup, name=’signup’),     path(‘product/<int:product_id>’, views.detail, name=’detail’),     path(‘fav_products’, views.fav_products, name=’fav_products’),     path(‘toggle_fav_product_status’,views.toggle_fav_product_status,name=’toggle_fav_product_status’)     path(‘cart’, views.cart, name=’cart’),     path(‘history’, views.history, name=’history’),]
app/views.py
from .models import Productfrom .forms import AddToCartFormfrom django.shortcuts import get_object_or_404, render, redirectfrom django.contrib.auth.decorators import login_requiredfrom django.contrib import messagesfrom django.views.decorators.http import require_POST
def index(request): return render(request, ‘app/index.html’)
def detail(request, product_id):     product = get_object_or_404(Product, pk=product_id)     if request.method==”POST”:         add_to_cart_form = AddToCartForm(request.POST)         if add_to_cart_form.is_valid():             num = add_to_cart_form.cleaned_data[‘num’]             if ‘cart’ in request.session:                 if str(product_id) in request.session[‘cart’]:                     request.session[‘cart’][str(product_id)] += num                 else:                     request.session[‘cart’][str(product_id)] = num             else:                 request.session[‘cart’] = {str(product_id): num}             messages.success(request, f”{product.name}を{num}個カートに入れました”)             return redirect(‘app:detail’, product_id=product.id)          add_to_cart_form = AddToCartForm()     return render(request, ‘app/detail.html’, {‘product’:product, ‘add_to_cart_form’:add_to_cart_form})
@login_requireddef fav_products(request):    products = request.user.fav_products.all()    return render(request, ‘app/index.html’, {‘products’: products})
@login_required@require_POSTdef toggle_fav_product_status(request):    product = get_object_or_404(Product,pk=request.POST[“product_id”])    user = request.user
    if product in user.fav_products.all()        user.fav_products.remove(product)    else:        user.fav_products.add(product)    return redirect(‘app:detail’, product_id=product.id)

@login_requireddef cart(request):    cart = request.session.get(‘cart’,{})    cart_products = {}    total_price = 0    for product_id, num in cart.items():        product = Product.objects.filter(id=product_id).first()        if product is None:            continue        cart_products[product] = num        total_price += product.price * num    return render(request, ‘app/cart.html’, {‘cart_products’:cart_product, ‘total_price’:total_price})
@login_requireddef history(request):    sales = Sale.objects.filter(user=request.user).order_by(‘-created_at’)    return render(request, ‘app/history.html’, {‘sales’:sales})
app/forms.py
from django.contrib.auth import get_user_modelfrom django.contrib.auth.forms import UserCreationFormfrom django import forms
class CustomUserCreationForm(UserCreationForm): class Meta: model = get_user_model() fields = (‘email’,)
class AddToCartForm(forms.Form):     num = forms.IntegerField( label=’数量’, min_value=1, required=True )②

get_user_model関数はsettings.pyのAUTH_USER_MODELで設定したモデルを呼び出す

②min_value=1は入力できる最小値を1に設定

app/models.py
from django.db import modelsfrom django.contrib.auth import get_user_model
class Product(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) price = models.PositiveIntegerField(default=0) image = models.ImageField(upload_to=’product’) def __str__(self): return self.name
class Sale(models.Model): product = models.ForeignKey(Product,on_delete=models.PROTECT) user = models.ForeignKey(‘users.User’,on_delete=models.PROTECT) amount = models.PositiveIntegerField(“購入個数”,default=0) price = models.PositiveIntegerField(“商品単価”) total_price = models.PositiveIntegerField(“小計”) created_at = models.DateTimeField(auto_now=True)

on_delete=models.PROTECTなのでproductが削除されてもsaleの情報は消えない

app/views.py
from django.shortcuts import render, redirectfrom django.contrib.auth import authenticate, loginfrom .forms import CustomUserCreationForm
def index(request):    products = Product.objects.all().order_by(‘-id’)    return render(request, ‘app/index.html’, {‘product’:products})def signup(request): if request.method == ‘POST’: form = CustomUserCreationForm(request.POST) if form.is_valid(): form.save() input_email = form.cleaned_data[‘email’] input_password = form.cleaned_data[‘password’] new_user = authenticate( email=input_email, password=input_password,)if new_user is not None: login(request, new_user) return redirect(‘app:index’) else: form = CustomuserCreationForm() return render(request, ‘app/signup.html’, {‘form’:form})
app/admin.py
from django.contrib import adminfrom .models import Product, Saleadmin.site.register(Product)admin.site.register(Sale)

userアプリ

users/models.py
from django.db import modelsfrom django.contrib.auth.models import PermissionsMixinfrom django.contrib.auth.base_user import AbstractBaseUserfrom django.utils import timezonefrom django.contrib.auth.base_user import BaseUserManagerfrom app.models import Product
class UserManager(BaseUserManager):    use_in_migrations = True    def _create_user(self, email, password, **extra_fields):          if not email:          raise ValueError(‘the given email must be set’)        email = self.normalize_email(email)        user = self.model(email=email, **extra_fields)        user.set_passwd(password)        user.save(using=self.db)        return user
    def create_user(self, email, password=None, **extra_fields):        extra_fields.setdefault(‘is_staff’, False)        extra_fields.setdefault(‘is_superuser’, False)        return self._create_user(email, password, **extra_fields)
    def create_superuser(self, email, password, **extra_fields):        extra_fields.setdefault(‘is_staff’, True)        extra_fields.setdefault(‘is_superuser’, True)        if extra_fields.get(‘is_staff’) is not True:            raise ValueError(‘Superuser must have is_staff=True’)        if extra_fields.get(‘is_superuser’) is not True:            raise ValueError(‘Superuser must have is_superuser=True’)        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):    initial_point = 50000    email = models.EmailField(“メールアドレス”, unique=True)    point = models.PositiveIntegerField(default=initial_point)    fav_products = models.ManyToManyField(Product, blank=True)    is_staff = models.BooleanField(“is_staff”, default=False)    is_active = models.BooleanField(“is_active”, default=True)    date_joined = models.DateTimeField(“date_joined”, default=timezone.now)
    objects = UserManager()    USERNAME_FIELD = “email”①    EMAIL_FIELD = “email”    REQUIRED_FIELDS = []②
    class Meta:        verbose_name = “user”        verbose_name_plural = “users”

①emailフィールドの情報でユーザーを1人に絞る

②createsuperuserする際に必須となるフィールドを指定(今回は空)

(USERNAME_FIELDで指定したフィールドとパスワードはデフォルトで必須)

users/admin.py
from django.contrib import adminfrom django.contrib.auth.admin import UserAdminfrom django.contrib.auth.forms import UserChangeForm, UserCreationFormfrom django.utils.translation import ugettext_lazy as _from .models import User
class MyUserChangeForm(UserChangeForm): class Meta: model = User fields = ‘__all__’
class MyUserCreationForm(UserCreationForm): class Meta: model = User fields = (‘email’,)class MyUserAdmin(UserAdmin): fieldsets = ( (None, {‘fields’:(‘email’,’password’,’fav_products’)}), (_(‘Permissions’),{ ‘fields’:( ‘is_active’, ‘is_staff’, ‘is_superuser’, ‘groups’, ‘user_permissions’) }), (_(‘Important dates’),{‘fields’:(‘last_login’,’date_joined’)}),)

add_fieldsets = ( (None,{ ‘classes’: (‘wide’,), ‘fields’: (‘email’,’password1’,’password2’), }),)

form = MyUserChangeFormadd_form = MyUserCreationFormlist_display = (‘email’,’is_staff’)list_filter = (‘is_staff’,’is_superuser’,’is_active’,’groups’)search_fields = (‘email’,)ordering = (‘email’,)
admin.site.register(User, MyUserAdmin)

デフォルトのUserモデルを削除してカスタムユーザーモデルでマイグレートする

rm db.sqlite3

python manage.py makemigrations

python manage.py migrate

テンプレートファイル

base.html
{% load static %}{% load humanize %}<!DOCTYPE html>
<html><head> <title>Djamazon</title> <link rel=”stylesheet” href=”{% static ‘css/style.css’ %}”></head><body><header> <h1><a href=”{% url ‘app:index’ %}”>Djamazon</a></h1> {% if request.user.is_authenticated %}          Point:{{ user.point | intcomma }}          <a href=”{% url ‘app:fav_products’ %}”>お気に入り</a>                <a href=”{% url ‘app:cart’ %}”>カート</a>                <a href=”{% url ‘app:history’ %}”>注文履歴</a>     <a href=”{% url ‘app:logout’ %}”>ログアウト</a> {% else %}   <a href=”{% url ‘app:login’ %}”>ログイン</a>        <a href=”{% url ‘app:signup’ %}”>サインアップ</a> {% endif %}</header><main>     {% for message in messages %}         {{ message }}     {% endfor %} {% block content %}{% endblock %}</main>
</body>
</html>
index.html
{% extends ‘app/base.html’ %}{% load humanize %}{% block content %}     {% if ‘fav_products’ in request.path %}お気に入り商品{% endif %}① {% for product in products %}          Point:{{ product.price | intcomma }}      {% endfor %}{% endblock %}

①requestされたurlにfav_productsが入っていればif内を表示

detail.html
{% extends ‘app/bae.html’ %}{% load humanize %}{% block content %} <img src=”{{ product.image.url }}”> <h2>{{ product.name }}</h2> <h4>{{ product.price | intcomma }}ポイント</h4>   {% if request.user.is_authenticated %}          <form method=”POST” action=”{% url ‘app:toggle_fav_product_status’ %}”>              {% csrf_token %}              <input type=”hidden” name=”product_id” value=”{{ product.id }}”>              {% if product in user.fav_products.all %}                  <input type=”submit” name=”submit” value=”お気に入りから外す”>              {% else %}                  <input type=”submit” name=”submit” value=”お気に入りに入れる”>              {% endif %}          </form>     {% endif %}     {% if request.user.is_authenticated %}         <form method=”POST” action=”{% url ‘app:detail’ product.id %}”>             {% csrf_token %}             {{ add_to_cart_form.as_p }}             <button type=”submit”>カートに追加する</button>         </form>     {% else %}         <a href=”{% url ‘app:login’ %}?next={{ request.path }}”>             <button>ログインして購入する</button>         </a>     {% endif %} <p>{{ product.description }}</p>{% endblock %}

{{product.price|intcomma}}で3ケタごとに区切る

settings.pyでdjango.contrib.humanizeとNUMBER_GROUPING = 3を書かないとダメ

signup.html
{% extends ‘app/base.html’ %}{% block content %}<form method=”POST” action=”{% url ‘app:signup’ %}”> {% csrf_token %} <label>email</label> {{ form.email }}{{ form.email.errors }} <label>password</label> {{ form.password1 }}{{ form.password1.errors }} <label>password(confirm)</label> {{ form.password2 }}{{ form.password2.errors }} <input type=”submit” value=”SIGNUP”></form>{% endblock %}
login.html
{% extends ‘app/base.html’ %}{% block content %}<form method=”POST”> {% csrf_token %} {% if form.errors %}<p>username or password mistake</p>{% endif %}<label>email</label><input name=”username”><label>password</label><input type=”password” name=”password”><input type=”submit” value=”LOGIN”></form>{% endblock %}
cart.html
{% extends ‘app/base.html’ %}{% load humanize %}{% block content %} {% for product, num in cart_products.items %} {{ product.name }} 価格:{{ product.price | intcomma }} 個数:{{ num | intcomma }} {% endfor %}{% endblock %}
history.html
{% extends ‘app/base.html’ %}{% load humanize %}{% block content %} {% for sale in sales %} {{ sale.product.name }} {{ sale.price | intcomma }} {{ sale.amount | intcomma }} {{ sale.total_price | intcomma }} {{ sale.created_at | date:”Y/m/d” }} {% endfor %}{% endblock %}