Macです。
####環境
venvで環境作ってdjangoインストールします。
$python -m venv <environmentName>
$cd <environmentName>
$source bin/activate
$pip install --upgrade pip
$pip install django==2.0.1
$django-admin startproject <projectName> .
$python manage.py startapp <applicationName>
2019年末でdjangoはバージョン3系です。何もしないでインストールするとそれになり、adminにログインできなくなる場合があるので、2系にしとくのが無難です。
以下で行きます。
environmentName = reh
projectName = rehabili
applicationName = reha
###settings.pyでDjangoの環境設定をいじります。
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ja'
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Tokyo'
###データベースへの作成 `python manage.py migrate`
###スーパーユーザの追加 `python manage.py createsuperuser` 適当に指示に従います。
###開発サーバの起動 `python manage.py runserver`
http://127.0.0.1:8000/ or http://localhost:8000/ をブラウザで開いてロケットが出てれば成功
###モデルの作成
from django.db import models
class SamplePost(models.Model):
postname = models.CharField('name', max_length=999)
postfrom = models.CharField('from', max_length=999, blank=True)
postlength = models.IntegerField('length', blank=True, default=0)
def __str__(self):
return self.postname
class SamplePost2(models.Model):
postname2 = models.ForeignKey(SamplePost, verbose_name='postname', related_name='samplepost2', on_delete=models.CASCADE)
comment = models.TextField('comment', blank=True)
def __str__(self):
return self.comment
####管理画面に追加
from django.contrib import admin
from reh.models import SamplePost, SamplePost2
admin.site.register(SamplePost)
admin.site.register(SamplePost2)
####アプリの追加
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'reh', #ここに作成したアプリ名を追加
]
makemigratoinsでデータベースに追加するための前処理をします。最後のアプリケーション名はなくても大丈夫ですが、プロジェクトが大きくなると多分長くなります。 `python manage.py makemigrations reh`
データベースに追加 `python manage.py migrate`
####管理画面へログイン
先ほど作ったスーパーユーザーでログイン
http://localhost:8000/admin/
####管理画面を修正
ここを参考にしました。管理画面の一覧から修正できる項目が増えます。
https://qiita.com/kaki_k/items/7b178ad39394a031b50d
from django.contrib import admin
from reh.models import SamplePost, SamplePost2
class SamplePostAdmin(admin.ModelAdmin):
list_display = ('id', 'postname', 'postfrom', 'postlength',) # 一覧に出したい項目
list_display_links = ('id', 'postname',) # 修正リンクでクリックできる項目
admin.site.register(SamplePost, SamplePostAdmin)
class SamplePost2Admin(admin.ModelAdmin):
list_display = ('id', 'comment',)
list_display_links = ('id', 'comment',)
raw_id_fields = ('postname2',) # 外部キーをプルダウンにしない(データ件数が増加時のタイムアウトを予防)
admin.site.register(SamplePost2, SamplePost2Admin)
####URL スキームの設計
アプリフォルダ内にurls.pyを作成し、プロジェクトのurls.pyからインクルードします。
from django.shortcuts import render
from django.http import HttpResponse
def reh_list(request):
return HttpResponse('reh一覧')
from django.urls import path
from reh import views
app_name = 'reh'
urlpatterns = [
path('list/', views.reh_list, name='reh_list'),
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('reh/', include('reh.urls')),
path('admin/', admin.site.urls),
]
以下のURLが生きてきます
http://127.0.0.1:8000/reh/list/
####フォームを作る
少し横道にそれて、普通にフォームを作ります。ただしこの作り方だとDBに反映できません。
### 追記です
def formInit(request):
params = {
'title':'Hello World',
'msg':'名前を入力してください',
}
return render(request,'reh/hello.html', params)
def formTest(request):
msg = request.POST['msg']
params = {
'title':'Hello World',
'msg':'hello '+msg+'!',
}
return render(request,'reh/hello.html', params)
from django.urls import path
from reh import views
app_name = 'reh'
urlpatterns = [
path('list/', views.reh_list, name='reh_list'),
path('formInit/', views.formInit, name='formInit'),
path('formTest/', views.formTest, name='formTest'),
]
{% load static %}
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>{{ msg }}</p>
<!--普通のHTMLと同様にactionを指定します-->
<form action="{% url 'reh:formTest' %}" method = "post">
{% csrf_token %} <!--CSRF対策-->
<label for = "msg">何か入れて</label>
<input id = "msg" type="text" name ="msg">
<input type="submit" value="input">
</form>
</body>
</html>
ブラウザ上のみでは普通に動きます。
このままじゃDBに反映できないので、Djangoのforms.py、Formクラスを使います。
差分の部分のみ書きます。
from .forms import formInitForm
def formInit(request):
# params = {
# 'title':'Hello World',
# 'msg':'名前を入力してください',
# }
# return render(request,'reh/hello.html', params)
params = {
'title':'Hello World',
'msg':'名前を入力してください',
'form': formInitForm(),
}
if (request.method=='POST'):
params['msg'] = 'こんにちは!'+request.POST['name']+'さん!<br>'+request.POST['area']+'にお住まいで<br>年齢は'+request.POST['age']+'歳なんですね!<br>よろしくお願いします。'
params['form']= formInitForm(request.POST)
return render(request,'reh/hello.html', params)
# def formTest(request):
# msg = request.POST['msg']
# params = {
# 'title':'Hello World',
# 'msg':'hello '+msg+'!',
# }
# return render(request,'reh/hello.html', params)
path('formInit/', views.formInit, name='formInit'),
# path('formTest/', views.formTest, name='formTest'),
テンプレート内はコメントアウトでも中のpython実行されちゃうんで、差分は各自確認ください。
{% load static %}
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>{{msg|safe}}</p>
<form action= "{% url 'reh:formInit' %}" method = "post">
{% csrf_token %}
<ul>
{{form.as_ul}} <!--ここがforms.pyの項目-->
</ul>
<input type="submit" value="input">
</form>
</body>
</html>
####CRUD/ create, read, update, delete
さて、横道から戻して、一覧から修正や削除、追加ができるようにします。
まずは一覧を作ります。
いくつかテンプレートhtml作るので、baseを作ります。適当にcss当ててます。
{% load i18n static %}
<!DOCTYPE html>{% get_current_language as LANGUAGE_CODE %}
<html lang="{{ LANGUAGE_CODE|default:'en-us' }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
h4{
font-size: 20px;
display: inline-block;
margin-right: 30px;
}
.container{
width: 100%;
max-width: 800px;
margin: 60px auto;
}
.btn{
text-decoration: none;
padding: 5px 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
button.btn{
font-size: 16px;
display: inline-block;
line-height: 1;
}
th,td{
min-width: 100px;
text-align: center;
}
table{
border-collapse:collapse;
margin:0 auto;
}
th{
color:#005ab3;
min-width: 120px;
}
td{
border-bottom:1px dashed #999;
}
th,tr:last-child td{
border-bottom:2px solid #005ab3;
}
td,th{
padding:10px;
}
form input{
padding: 5px;
font-size: 20px;
margin-bottom: 20px;
}
form label{
padding: 5px;
font-size: 20px;
margin-bottom: 20px;
min-width: 90px;
display: inline-block;
}
.flex{
display: flex;
}
</style>
{% block extra_css %}{% endblock %}
<title>{% block title %}My rehs{% endblock %}</title>
</head>
<body>
<div class="container">
{% block content %}
{{ content }}
{% endblock %}
</div>
{% block extra_js %}{% endblock %}
</body>
</html>
{% extends "reh/base.html" %}
{% block title %}一覧{% endblock title %}
{% block content %}
<h4>一覧</h4>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">NAME</th>
<th scope="col">FROM</th>
<th scope="col">LENGTH</th>
</tr>
</thead>
<tbody>
{% for reh in rehs %} <!-- ① -->
<tr>
<th scope="row">{{ reh.id }}</th>
<td>{{ reh.postname }}</td>
<td>{{ reh.postfrom }}</td>
<td>{{ reh.postlength }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
① {% for reh in rehs %} の部分で一覧を読み込みますので、views.pyを修正します。
def reh_list(request):
# return HttpResponse('一覧')
#ここでSamplePostをid順に全て持ってきてrehsに格納
rehs = SamplePost.objects.all().order_by('id')
#renderメソッドの第3引数に辞書を入れられるので、上で持ってきたrehsという名前でrehsを入れる。
return render(request, 'reh/reh_list.html', {'rehs': rehs})
これで http://localhost:8000/reh/list/ に一覧が表示されます。
次に追加ボタンを作成します。
{% extends "reh/base.html" %}
{% block title %}一覧{% endblock title %}
{% block content %}
<h4>一覧</h4>
<!-- ここに追加 -->
<a href="{% url 'reh:reh_add' %}" class="btn">追加</a>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">NAME</th>
<th scope="col">FROM</th>
<th scope="col">LENGTH</th>
</tr>
</thead>
<tbody>
{% for reh in rehs %} <!-- ① -->
<tr>
<th scope="row">{{ reh.id }}</th>
<td>{{ reh.postname }}</td>
<td>{{ reh.postfrom }}</td>
<td>{{ reh.postlength }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
{% url 'reh:reh_add' %} reh_add をurls.pyに追加します。
reh_edit というviewを追加します。views.pyのreh_editを呼び出すようにします。
path('list/add/', views.reh_edit, name='reh_add'),
def reh_edit(request, reh_id=None):
reh_temp = SamplePost()
if request.method == 'POST':
#追加ページでフォームをPOSTする場合の処理
form = SamplePostForm(request.POST, instance=reh_temp)
#POSTされたformのバリデーション
if form.is_valid():
reh_temp = form.save(commit=False)
reh_temp.save()
#formの保存が終わったら一覧に戻ります
return redirect('reh:reh_list')
else: #GET時、一覧から追加ボタンを押した時はこちらを表示
#SamplePostインスタンスからフォームを作成
form = SamplePostForm(instance=reh_temp)
#辞書にformとreh_id=Noneを入れてrenderメソッドで編集用ページ遷移させます
return render(request, 'reh/reh_edit.html', dict(form=form, reh_id=reh_id))
上でのformのモデルをforms.pyで作ります。
from django.forms import ModelForm
from reh.models import SamplePost
class SamplePostForm(ModelForm):
#すでにSamplePostで定義してあるプロパティを使用する場合はMetaクラスで
class Meta:
model = SamplePost
# 明示的もしくはモデルの一部のプロパティだけ使う場合
fields = ('postname', 'postfrom', 'postlength', )
編集用ページテンプレートを作成します。
{% extends "reh/base.html" %}
{% block title %}タイトル{% endblock title %}
{% block content %}
<!-- formのアクションとして、formの値をreh_editビューに送ります -->
<form action="{% url 'reh:reh_add' %}" method="post">
{% csrf_token %}
#後述するforms.pyを呼びます
{{ form.as_ul }}
<div>
<button type="submit" class="btn">送信</button>
</div>
</form>
<a href="{% url 'reh:reh_list' %}" class="btn">戻る</a>
{% endblock content %}
次に簡単な削除を(確認画面とかなしでいきなり消えるので簡単)
reh_idを取得してそれを消します。
templateにボタンを追加し、id付きで次に作るviewに飛ばします。
{% extends "reh/base.html" %}
{% block title %}一覧{% endblock title %}
{% block content %}
<h4>一覧</h4>
<!-- ここに追加 -->
<a href="{% url 'reh:reh_add' %}" class="btn">追加</a>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">NAME</th>
<th scope="col">FROM</th>
<th scope="col">LENGTH</th>
<th scope="col">操作</th>
</tr>
</thead>
<tbody>
{% for reh in rehs %} <!-- ① -->
<tr>
<th scope="row">{{ reh.id }}</th>
<td>{{ reh.postname }}</td>
<td>{{ reh.postfrom }}</td>
<td>{{ reh.postlength }}</td>
<td>
<!-- aタグのリンク先にreh_del viewにして、引数にIDつける -->
<a href="{% url 'reh:reh_del' reh_id=reh.id %}" class="btn">削除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
def reh_del(request, reh_id):
#指定したIDのインスタンスがある場合はそれを、ない場合は404(django.http.Http404)呼び出し、
#その後deleteして一覧にリダイレクト。
reh = get_object_or_404(SamplePost, pk=reh_id)
reh.delete()
return redirect('reh:reh_list')
URLはこれですね。
path('list/del/<int:reh_id>/', views.reh_del, name='reh_del'),
最後に修正ボタンを。
一覧ページにボタンをつけましょう。
{% extends "reh/base.html" %}
{% block title %}一覧{% endblock title %}
{% block content %}
<h4>一覧</h4>
<!-- ここに追加 -->
<a href="{% url 'reh:reh_add' %}" class="btn">追加</a>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">NAME</th>
<th scope="col">FROM</th>
<th scope="col">LENGTH</th>
<th scope="col">操作</th>
</tr>
</thead>
<tbody>
{% for reh in rehs %} <!-- ① -->
<tr>
<th scope="row">{{ reh.id }}</th>
<td>{{ reh.postname }}</td>
<td>{{ reh.postfrom }}</td>
<td>{{ reh.postlength }}</td>
<td>
<!-- 修正ボタン追加 これも引数にidを。追加を同じviewを使います。 -->
<a href="{% url 'reh:reh_mod' reh_id=reh.id %}" class="btn ">修正</a>
<a href="{% url 'reh:reh_del' reh_id=reh.id %}" class="btn">削除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}
views.pyのreh_editを修正します。
def reh_edit(request, reh_id=None):
#追加の場合との場合わけは、idを引数に必要とするかどうかなのでそれを利用
#reh_tempに値が入っているかであとは追加と同じ処理
if reh_id:
#修正場合の処理。インスタンスは既存の値
reh_temp = get_object_or_404(SamplePost, pk=reh_id)
else:
#こっちが新規で追加する場合の処理。インスタンスは初期値になっている
reh_temp = SamplePost()
if request.method == 'POST':
form = SamplePostForm(request.POST, instance=reh_temp)
if form.is_valid():
reh_temp = form.save(commit=False)
reh_temp.save()
return redirect('reh:reh_list')
else:
form = SamplePostForm(instance=reh_temp)
return render(request, 'reh/reh_edit.html', dict(form=form, reh_id=reh_id))
path('list/mod/<int:reh_id>/', views.reh_edit, name='reh_mod'),
編集用ページテンプレートも追加のみでなく修正にも対応させます。
{% extends "reh/base.html" %}
{% block title %}タイトル{% endblock title %}
{% block content %}
<!-- views.pyと同様に、reh_idの有無で判断します -->
{% if reh_id %}
<form action="{% url 'reh:reh_mod' reh_id=reh_id %}" method="post">
{% else %}
<form action="{% url 'reh:reh_add' %}" method="post">
{% endif %}
{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<div class="flex">
<button type="submit" class="btn">送信</button>
<a href="{% url 'reh:reh_list' %}" class="btn">戻る</a>
</div>
</form>
{% endblock content %}