前置き
独学で、子供の成長アプリを作った時のことを、記録として残していきます。
間違っているところなどあれば、ご連絡お願いします。
①Djangoのようこそページへたどり着くまで
②NginxでDjangoのようこそページへたどり着くまで
③カスタムユーザーを作ってadminにたどり着く
④ログインログアウトをしよう
⑤ユーザー登録(サインイン)機能を作ろう
⑥ユーザーごとのデータ登録できるようにする〜CRU編 <--ここです
⑦ユーザーごとのデータ登録できるようにする〜削除編
⑧画像ファイルのアップロード
⑨身長体重を記録する@一括削除機能つき
⑩成長曲線グラフを描いてみよう
⑪本番環境へデプロイ+色々手直し
Goal
ユーザーごとのデータを登録できるようにする。CRUDのうちCRUまでいきます。
作るのは、ユーザーごとに子供の情報を登録できるようにします。
Model
名前、性別に加えて、あとで身長体重の成長曲線が書けるよう、生年月日を持ちます。
Modelを直したら、マイグレーションを実施。(コマンドは省略)
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from django.utils import timezone
class UserManager(BaseUserManager):
(略)
class User(AbstractBaseUser, PermissionsMixin):
(略)
class KidsProfile(models.Model):
GENDER_CHOICES = (
('1', '女性'),
('2', '男性'),
)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=20, blank=False)
gender = gender = models.CharField(max_length=2, choices=GENDER_CHOICES, blank=False)
birthday = models.DateField(null=False, blank=False)
def __str__(self):
title = self.name
return title
モデルを追加したら、adminで操作できるようにしましょう。
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.utils.translation import ugettext_lazy as _
from .models import User, KidsProfile #モデル追加
class MyUserChangeForm(UserChangeForm):
(略)
class MyUserCreationForm(UserCreationForm):
(略)
class MyUserAdmin(UserAdmin):
(略)
admin.site.register(User, MyUserAdmin)
admin.site.register(KidsProfile) #追加
Form
pythonのDateFieldはyyyy-mm-dd形式なので、入力時のバリデーションが面倒。
GUI的に入力しやすくするため、datetimepickerを入れます。
このフォームを入力するのはログインしてからなので、
Modelでは保有しているuser情報はFormでは見せないようにしてます。
(user情報はviewの中でシステム的に持ち回る)
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.forms import UserCreationForm
from .models import KidsProfile
import bootstrap_datepicker_plus as datetimepicker
User = get_user_model()
class SignUpForm(UserCreationForm):
(略)
class LoginForm(AuthenticationForm):
(略)
class KidsProfileForm(forms.ModelForm):
class Meta:
model = KidsProfile
fields = ('name', 'gender', 'birthday')
widgets = {
'birthday': datetimepicker.DatePickerInput(
format='%Y-%m-%d'),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', '')
super(KidsProfileForm, self).__init__(*args, **kwargs)
Django==2.2.2
psycopg2==2.8.4
uwsgi==2.0.17
django-bootstrap4==1.1.1
django-bootstrap-datepicker-plus==3.0.5 #追加
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users.apps.UsersConfig',
'bootstrap4',
'bootstrap_datepicker_plus', #追加
]
View
kids_profile_add関数では、POSTで受け取ったformに加えて
request.userで取得したユーザー情報を付与して保存してます。
kids_profile_edit関数では、それに加えて変更したい情報を事前に表示しておきたいので、
データのIDをURL経由で受け取ります。
#子供情報追加
@login_required
def kids_profile_add(request):
user_name = request.user
if request.method == 'POST':
form = KidsProfileForm(request.POST, user = user_name)
if form.is_valid():
data = form.save(commit=False)
data.user = user_name
data.save()
return redirect('users:mypage')
else:
form = KidsProfileForm(user = user_name)
return render(request, 'users/kids_profile_add.html', {'form': form})
#子供情報編集
@login_required
def kids_profile_edit(request, kidsProfileId):
kidsProfileData = KidsProfile.objects.get(pk=kidsProfileId)
if request.method == 'POST':
form = KidsProfileForm(request.POST)
if form.is_valid():
data = form.save(commit=False)
data.id = kidsProfileData.id
data.user = request.user
data.save()
return redirect('users:mypage')
else:
form = KidsProfileForm(
{
'name' : kidsProfileData.name ,
'gender' : kidsProfileData.gender ,
'birthday' : kidsProfileData.birthday
},
)
return render(request, 'users/kids_profile_edit.html', {'form': form})
HTML
_addも_editも、テンプレートはほぼ一緒。
{{ form.media }}を書かないと、datetimepickerが動かないので書く。
{% extends 'base.html' %}
{% block content %}
<!--日付入力フォーマット用-->
{{ form.media }}
<div class="col-md-12 col-lg-5">
<h2>New data</h2>
<form method="POST" class="post-form">{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="save btn btn-primary">Save</button>
</form>
</div>
{% endblock %}
{% extends 'base.html' %}
{% block content %}
<!--日付入力フォーマット用-->
{{ form.media }}
<div class="col-md-12 col-lg-5">
<h2>Data Edit</h2>
<form method="POST" class="post-form">{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="save btn btn-primary">Save</button>
</form>
</div>
{% endblock %}
ユーザーに紐づく子供の情報をTable形式で表示します。
子供の情報は複数人分が登録されるので、for文でレコード分だけ表示します。
{% extends 'base.html' %}
{% block content %}
<div class="col-md-12 col-lg-5">
<h2>My Page</h2>
<br>
<br>
<table class = "table">
<tr>
<td>ユーザー名</td>
<td>{{ user }}</td>
</tr>
</table>
<table class = "table table-hover">
<thead class = "thead-dark">
<tr>
<th>名前</th>
<th>性別</th>
<th>誕生日</th>
<th></th>
<th></th>
</tr>
</thead>
{% for kids_profile in kidsProfiles %}
<tr>
<td>{{ kids_profile.name }}</td>
<td>{{ kids_profile.get_gender_display }}</td>
<td>{{ kids_profile.birthday }}</td>
<td><a href="{% url 'users:kids_profile_edit' kids_profile.id %}" class="btn btn-success btn-sm">編集</a></td>
<td><button type="button" class="btn btn-danger btn-sm del_confirm">削除</button></td>
</tr>
{% endfor%}
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a href="{% url 'users:kids_profile_add' %}" class="btn btn-primary btn-sm" role="button">追加</a></td>
</tr>
</table>
</div>
{% endblock content %}
urls
新しいページを作ったので、URLのパスを通す。
kidsProfileIdをurlsで指定することで、URLを使ってHTMLとPythonで変数を受け渡す。
app_name = 'users'
urlpatterns = [
path('', views.mypage, name='mypage'),
path('signup/', views.signup, name='signup'),
path('mypage/', views.mypage, name='mypage'),
path('login/', views.login_mypage.as_view(), name='login'),
path('logout/', views.logout.as_view(), name='logout'),
path('kids_profile_add/', views.kids_profile_add, name='kids_profile_add'), #追加
path('kids_profile_edit/<kidsProfileId>', views.kids_profile_edit, name='kids_profile_edit'),#追加
]
動かす!
登録がない状態。
登録画面。datetimepickerだと、こんな感じで表示される。
ちなみにスマホでやると、ちょっとやり辛い。解消方法はあるようだが、試してはいない。
編集すると、こんな感じ。各項目、元々の情報が入った状態で、変更可能なフォームが表示される。
登録されると、こんな感じ。この時点では削除ボタンはダミー。