Django on UbuntuでWebアプリ開発

作業記録です。
随時追記します。
環境はsakuraのvpsですが初期状態ではありません。
[Djangoの公式サイト](https://docs.djangoproject.com/ja/2.0/)を参照しています。

#インストール
##Ubuntuのバージョン確認
```
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
```
##Pythonのバージョン確認
```
$ python -V
Python 2.7.12
$ python3 -V
Python 3.5.2
```

##Djangoがインストールされていないことを確認
```
$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'django'
```

##インストール
```
$ sudo pip3 install django
(中略)
Successfully installed django-2.0.5 pytz-2018.4
```

##動作確認
```
$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> print(django.get_version())
2.0.5
```
#チュートリアル
##プロジェクト作成
```
$ django-admin startproject mysite
$ tree mysite/
mysite/
├── manage.py
└── mysite
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

1 directory, 5 files
```
##サーバ起動
```
$ cd mysite/
$ python3 manage.py runserver

Performing system checks...

System check identified no issues (0 silenced).

You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

May 09, 2018 - 16:00:30
Django version 2.0.5, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```
##VPSファイアウォール設定変更
```
(以下メモです。そのうち最適な手順を記載するかもしれません。)
$ sudo iptables -I INPUT 1 -p tcp -m tcp --dport 8000 -j ACCEPT
で変更してもローカル端末から接続できなかったため、
ufwをdisabledにしたり、vimで/etc/iptables/iptables.rulesを編集。
しかし接続できず。
$ lsof -i
で、localhostをlistenしていることを確認。
以下のコマンド（x.x.x.xはVPSのIPアドレス）で外部からの接続が可能に。
$ python3 manage.py runserver x.x.x.x:8000
ただし「DisallowedHost」ページが表示された。
```
##Djangoの設定変更後、再起動
```
$ vi mysite/settings.py
ALLOWED_HOSTS = ["x.x.x.x"]
$ python3 manage.py runserver x.x.x.x:8000
```
ロケットの画像と
「The install worked successfully! Congratulations!」
が表示された。

##アプリケーション作成
```
$ python3 manage.py startapp polls
$ tree
.
├── db.sqlite3
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-35.pyc
│   │   ├── settings.cpython-35.pyc
│   │   ├── urls.cpython-35.pyc
│   │   └── wsgi.cpython-35.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── polls
    ├── admin.py
    ├── apps.py
    ├── __init__.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

4 directories, 17 files
```
##view記述
```
$ vi polls/views.py
```
```
from django.shortcuts import render

# Create your views here.
```
を

```
from django.shortcuts import render
from django.http import HttpResponse


def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")
```

に変更。

##URLconfを作成
```
$ vi polls/urls.py
```
```
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]
```
##ルートのURLconfに反映
```
$ vi mysite/urls.py
```

```
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]
```
を

```
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
   path('polls/', include('polls.urls')),
   path('admin/', admin.site.urls),
]
```
に変更。

サーバを再起動して、
```http://x.x.x.x:8000/polls/```
にアクセスしたら、
「Hello, world. You're at the polls index.」
と表示された。

##モデルを作成
```
$ vi polls/models.py
```

```
from django.db import models

# Create your models here.
```
を

```
from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
```
に変更。

##モデルを有効化
```
$ vi mysite/settings.py 
```

```
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
```

を

```
INSTALLED_APPS = [
    'polls.apps.PollsConfig',    
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
```

に変更。

##モデル変更をDjangoに通知
```
$ python3 manage.py makemigrations polls
Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Choice
    - Create model Question
    - Add field question to choice
```


##管理サイト等のテーブル作成
```
$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying polls.0001_initial... OK
  Applying sessions.0001_initial... OK
```

##管理ユーザを作成
```
$ python3 manage.py createsuperuser
Username (leave blank to use 'ubuntu'): ***
Email address: ***
Password: 
Password (again): 
Superuser created successfully.
```

##Pollsアプリを管理画面に表示する設定
```
$ vi polls/admin.py 
```

```
from django.contrib import admin

# Register your models here.
```

を

```
from django.contrib import admin

from .models import Question

admin.site.register(Question)
```
に変更。

サーバを再起動して、
```http://x.x.x.x:8000/admin/```
にアクセスしたら、ログインフォームが表示されたのでログイン。

Qestionデータのメンテが画面から可能になったことを確認した。

##ここまでの感想とか
・Timezoneを変える必要がある
・httpsに対応する必要がある
・管理画面でのデータメンテ機能は使いやすい
　・特に保存ボタンが3種類ある点に好感が持てた
　　[Save and add another][Save and continue edit][Save]
　　※保存意図のパターンを想像すれば当然の仕様だが中々お目にかかれない。
　・トップページにRecent actionsのリストがリンク表示され、データ編集ページに直接遷移できる
・簡易ではあるがデータの更新履歴が表示できる
・提供されている管理画面が丁寧に作られているので、プロダクトの他の部分の品質にも期待ができる
・最新のドキュメントではmigrateが非推奨というような記述を見かけたので要調査
・ユーザのパスワードが暗号化されているかテーブルを検索してみよう -> sh256で？暗号化されている模様
・ログ全般について確認してみよう
・最初から管理画面を使えるようにして、アプリやモデルの作成を画面からできるようにした方が便利では？
　※インストールオプションでの制御ありで。

##アプリケーションの作成
・公式サイトのコピペで汎用ビューの使用まで進むことができました。

##言語・Timezoneの変更
```
$ vi settings.py
```
```
LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'
```

を

```
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'
```
に変更後
```http://x.x.x.x:8000/```
にアクセスしたところ
「The install worked successfully! Congratulations!」
が
「インストールは成功しました！おめでとうございます！」
に変わっていた。