EC site
基本設定
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 %} |