LoginSignup
1
1

More than 3 years have passed since last update.

【 Docker+Nginx+Django+RDS】WEBアプリができるまで⑨身長体重を記録する@一括削除機能つき

Last updated at Posted at 2020-02-12

前置き

独学で、子供の成長アプリを作った時のことを、記録として残していきます。
間違っているところなどあれば、ご連絡お願いします。
 ①Djangoのようこそページへたどり着くまで
 ②NginxでDjangoのようこそページへたどり着くまで
 ③カスタムユーザーを作ってadminにたどり着く
 ④ログインログアウトをしよう
 ⑤ユーザー登録(サインイン)機能を作ろう
 ⑥ユーザーごとのデータ登録できるようにする〜CRU編
 ⑦ユーザーごとのデータ登録できるようにする〜削除編
 ⑧画像ファイルのアップロード
 ⑨身長体重を記録する@一括削除機能つき <--ここです
 ⑩成長曲線グラフを描いてみよう
 ⑪本番環境へデプロイ+色々手直し

Goal

身長と体重を記録できるようにする。(次の章でグラフ化するデータを登録)

やることとポイントのまとめ

この章で実装するのは、基本的に⑧で作ったもの構成と同じ。
1つ違うのは、レコードの一括削除機能をつけているところ。

Template→Viewへ、削除対象レコードのIDを渡すところが前回と違う。

あとは、Djangoの基本に則って、、、
①新しいAppを作る→setting.pyとurls.pyにAppを作ったことを知らせる
②Modelを作ろう→Migrationする。admin.pyにmodelを追加する
③Templateを作ろう→urls.pyでURLの体系を指定しよう
④Viewを作ろう→Modelを扱いやすいようFormも要るね

①APP作成〜プロジェクト内の指定

docker-compose run web python ./manage.py startapp phys
setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users.apps.UsersConfig',
    'shoes.apps.ShoesConfig',
    'phys.apps.PhysConfig', #追加
    'bootstrap4',
    'bootstrap_datepicker_plus',
    'django_cleanup.apps.CleanupConfig',
]
mysite/urls.py
from django.contrib import admin
from django.urls import path, include
from . import settings
from django.contrib.staticfiles.urls import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('users.urls')),
    path('',include('shoes.urls')),
    path('',include('phys.urls')), #追加
]

urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

②Model作成

phys/models.py
from django.db import models
from django.conf import settings
from django.utils import timezone
from users.models import KidsProfile

class PhysData(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    kidsProfile = models.ForeignKey(KidsProfile, on_delete=models.CASCADE)
    weight = models.DecimalField(
                max_digits=6,
                decimal_places=3
             )
    height = models.DecimalField(
                max_digits=5,
                decimal_places=2
             )
    date   = models.DateField(default=timezone.now)

    def __str__(self):
        return self.kidsProfile.name + str(self.date)
phys/admin.py
from django.contrib import admin
from .models import PhysData

admin.site.register(PhysData)

③テンプレート〜URL設計

phys_data_addとphys_data_editは省略。
前回の章で作ったものと、変わらないです。

phys/phys_data_list.html
{% extends 'base.html' %}

{% block content %}
<div class="row">
    <div class="col-md-12 col-lg-2">
        <div class="list-group">
          {% for kidsProfile in kidsProfiles %}
            <a href="/phys/list/{{kidsProfile.id}}" class="list-group-item list-group-item-action">{{kidsProfile.name}}</a>
          {% endfor %}
        </div>
    </div>
    <div class="col-md-12 col-lg-10 overflow-auto">
        <form method="post" action="{% url 'phys:phys_data_delete' %}">
        <table class="table table-hover">
          <thead class="thead-dark">
            <tr>
              <th>名前</th>
              <th>日付</th>
              <th>体重(kg)</th>
              <th>身長(cm)</th>
              <th>修正</th>
              <th>削除</th>
            </tr>
          </thead>
      {% for data_post in data_posts %}
          <tr>
            <td class="text-center">{{data_post.kidsProfile.name }}</td class="text-center">
            <td class="text-center">{{data_post.date }}</td>
            <td class="text-center">{{data_post.weight }}</td>
            <td class="text-center">{{data_post.height }}</td>
            <td class="text-center"><a href="{% url 'phys:phys_data_edit' data_post.pk %}" class="btn btn-success btn-sm" role="button">編集</a></td>
            <td class="text-center"><input type="checkbox" name="delete_ids" value="{{ data_post.pk }}"></input></td>
          </tr>
          {% endfor %}
          <tr>
            <td>
                <a href="{% url 'phys:phys_data_add' %}" role="button" class="btn btn-primary mr-auto">追加</a>
            </td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td class="text-center">
              {% csrf_token %}
              <input type="submit" value="一括削除" class="btn btn-danger float-right">
            </td>
          </tr>
        </table>
        </form>
    </div>
{% endblock %}
phys/urls.py
from django.urls import path
from . import views

app_name = 'phys'

urlpatterns = [
    path('phys/list/', views.phys_data_list, name='phys_data_list'),
    path('phys/list/<kidsProfileId>', views.phys_data_list, name='phys_data_list'),
    path('phys/data_add/', views.phys_data_add, name='phys_data_add'),
    path('phys/data_edit/<DataPostId>', views.phys_data_edit, name='phys_data_edit'),
    path('phys/data_delete/', views.phys_data_delete, name='phys_data_delete'),
]

④ViewとModel

phys/views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .models import PhysData
from users.models import KidsProfile
from .forms import PhysDataForm, PhysDataEditForm



#身長体重データを昇順で返却
@login_required
def phys_data_list(request, **kwargs):
    user_name = request.user
    if len(kwargs) > 0:
        kidsProfileId = kwargs["kidsProfileId"]
    else:
        kidsProfileId = KidsProfile.objects.filter(user=user_name).order_by('id')[0]

    kids_profiles = KidsProfile.objects.filter(user=user_name)

    data_posts = PhysData.objects.filter(user=user_name, kidsProfile=kidsProfileId).order_by('date')
    params = {
        'data_posts': data_posts,
        'kidsProfiles' : kids_profiles,
    }

    return render(request, 'phys/phys_data_list.html', params)

#身長体重データを新規登録する
@login_required
def phys_data_add(request):
    user_name = request.user
    if request.method == 'POST':
      form = PhysDataForm(request.POST, user = user_name)
      if form.is_valid():
        data = form.save(commit=False)
        data.user = user_name
        data.save()
        return redirect('phys:phys_data_list')
    else:
      form = PhysDataForm(user = user_name)
    return render(request, 'phys/phys_data_add.html', {'form': form})

#身長体重データを編集する
@login_required
def phys_data_edit(request, DataPostId):
    physData = PhysData.objects.get(pk=DataPostId)
    if request.method == 'POST':
      form = PhysDataEditForm(request.POST)
      if form.is_valid():
        data = form.save(commit=False)
        data.user = request.user
        data.kidsProfile = physData.kidsProfile
        data.id = physData.id
        data.save()
        return redirect('phys:phys_data_list')
    else:
      form = PhysDataEditForm(
        {
          'weight' : physData.weight ,
          'height' : physData.height ,
          'date' : physData.date
        },
        user = request.user
      )
    return render(request, 'phys/phys_data_edit.html', {'form': form})

#身長体重データを削除する
@login_required
def phys_data_delete(request):
    delete_ids = request.POST.getlist('delete_ids')
    PhysData.objects.filter(pk__in=delete_ids).delete()
    return redirect('phys:phys_data_list')
phys/forms.py
from django import forms
from .models import PhysData
from users.models import KidsProfile
import bootstrap_datepicker_plus as datetimepicker



class PhysDataForm(forms.ModelForm):
    class Meta:
        model = PhysData
        fields = ('kidsProfile', 'weight', 'height', 'date',)
        widgets = {
            'date': datetimepicker.DatePickerInput(
                           format='%Y-%m-%d'),
        }

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user','')
        super(PhysDataForm, self).__init__(*args, **kwargs)
        self.fields['kidsProfile'] = forms.ModelChoiceField(queryset=KidsProfile.objects.filter(user=user))

class PhysDataEditForm(forms.ModelForm):
    class Meta:
        model = PhysData
        fields = ('weight', 'height', 'date',)
        widgets = {
            'date': datetimepicker.DatePickerInput(
              format='%Y-%m-%d',
              ),
        }

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user','')
        kidsProfileId = kwargs.pop('kidsProfileId','')
        super(PhysDataEditForm, self).__init__(*args, **kwargs)

できあがり

こんな形になります。削除レコードはチェックボックス形式で纏めて指定&削除可能。
スクリーンショット 2020-02-13 01.34.59.png
登録画面は、普通。編集画面も、ほぼ同様。(子供の名前を選ばない程度)
スクリーンショット 2020-02-13 01.35.10.png

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1