Django の始め方（デプロイ前まで）

####目標
- Djangoの基本的な使い方を整理する。
- 簡単なアプリを作成する。

####ステップ１

#####Django のインストール
```python
pip install django
```

#####プロジェクトの作成
```python
django-admin startproject [project name]
```

プロジェクト名を project1 とする。

実行が終了すると、プロジェクト名のフォルダができ、 その下にproject1 フォルダと、manage.py が作成される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/ad9bf0c6-8d86-d525-2a5b-43df7eb030e2.png)

その project1/project1 の下に４つのファイルがある。 

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/915e9cf1-c540-64cb-9c8f-ef4fb7021f48.png)

次に、↓ を実行すると、

```python
python project1/manage.py runserver
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/55c61cfa-7ae9-c084-d613-0b1a15c2a5d7.png)

と動き、アクセスすると

http://localhost:8000/

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/9ad2b9cd-3307-e56c-4dc3-9df5459b1b4a.png)


####ステップ２

#####設定ファイル (setting.py) の変更

project1/settings.py

```python
LANGUAGE_CODE = 'ja'  # 変更

TIME_ZONE = 'Asia/Tokyo'  # 変更
```

#####アプリケーションの作成
↓ を実行。アプリケーション名を app1 とする。

```python
cd project1
python manage.py startapp app1
```

project1 フォルダーの中に app1 フォルダーが作られる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/0431d9f5-e3fb-88ad-3762-0630c6dd931e.png)


project1/settings.py

```python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app1',  # 追加
]
```


#####View関数の作成

app1/views.py

```python
from django.http.response import HttpResponse

def hello_world(request):  # 追加
    return HttpResponse('Hello World!')  # 追加
```

#####URLパターンの設定

app1 アプリケーションに urls.py を作成し、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/ebaf4998-7a97-8367-6a04-3af80c320ebf.png)

以下を追加する。

app1/urls.py

```python
# 全て追加
from django.urls import path
from . import views

urlpatterns = [
    path('hello/', views.hello_world, name='app1_hello_world'),
]
```

project1 フォルダ内にある urls.py に以下を追加する。

project1/urls.py

```python
from django.contrib import admin
from django.urls import path, include  # 追加

urlpatterns = [
    path('app1/', include(('app1.urls', 'app1'),)),  # 追加
    path('admin/', admin.site.urls),
]
```

#####動作確認
↓ を実行し、アクセスする。

```python
python project1/manage.py runserver
```

http://127.0.0.1:8000/app1/hello/ 

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/59a381b6-5afd-eb65-b44a-52e2b72fc11b.png)


####ステップ３

#####設定ファイル (settings.py) にテンプレートを置くフォルダを指定

```python
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 追加
        'APP_DIRS': True,
```

#####テンプレートを置くフォルダの作成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/21371ced-dfbc-e26a-fc0e-7264aadfbb55.png)

#####テンプレート (hello.html) の作成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/aa677ea3-cad7-b4a4-418a-ee6548c4bd9d.png)


templates/app1/hello.html

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
Hello Template!
</body>
</html>
```

#####View関数の作成

app1/views.py

```python

from django.http.response import HttpResponse
from django.shortcuts import render  # 追加

def hello_world(request):
    return HttpResponse('Hello World!')

def hello_template(request):  # 追加
    return render(request, 'app1/hello.html')  # 追加
```

#####URLパターンの設定

app1/urls.py

```python
urlpatterns = [
    path('hello/', views.hello_world, name='app1_hello_world'),
    path('template/', views.hello_template, name='app1_hello_template'),  # 追加
]
```

#####動作確認
```
python manage.py runserver
```

http://127.0.0.1:8000/app1/template

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/be9b6e32-efb1-49aa-7e0d-3c9d653dd512.png)


####ステップ４

#####Formクラスの作成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/957e0f36-4ccb-5062-4dd8-abef3fb571bd.png)

app1/forms.py

```python
from django import forms

class HelloForm(forms.Form):
    your_name = forms.CharField(
        label='名前',
        max_length=20,
        required=True,
        widget=forms.TextInput()
    )
```


#####View関数の作成

app1/views.py

```python
def hello_forms(request):
    form = forms.HelloForm(request.GET or None)
    if form.is_valid():
        message = 'データ検証に成功しました'
    else:
        message = 'データ検証に失敗しました'
    d = {
        'form': form,
        'message': message,
    }
    return render(request, 'forms.html', d)
```

#####テンプレート (base.html) の作成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/497ea1cc-dc6f-8a18-060f-2121def473b2.png)

templates/base.html

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
```

#####テンプレート (forms.html) の作成

templates/forms.html

```html
{% extends "base.html" %}

{% block body %}
  {{ message }}
  <hr>
  <form method="get" action="">
    {{ form.errors.your_name }}
    <label>{{ form.your_name.label }} {{ form.your_name }}</label><br>

    {{ form.errors.gender }}
    <label>{{ form.gender.label }} {{ form.gender }}</label><br>

    {{ form.errors.memo }}
    <label style="vertical-align: top;">{{ form.memo.label }} {{ form.memo }}</label><br>

    <input type="submit" value="送信">
  </form>
{% endblock %}
```

#####URLパターンの設定

app1/urls.py

```python
from django.urls import path
from . import views

urlpatterns = [
    path('hello/', views.hello_world, name='app1_hello_world'),
    path('template/', views.hello_template, name='app1_hello_template'),
    path('forms/', views.hello_forms, name='app1_hello_forms'),  # 追加
]
```

#####動作確認

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/6d81a028-b20c-ffdd-7234-cc9e448a5876.png)


####ステップ５

#####計算モデルの保存
事前に学習、保存した XGBoost モデルを配置する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/598c55ce-0bb1-5547-c633-ccc7aa748fc2.png)


#####Formクラスの作成
XGBoost モデルに必要な11個の引数を入力するためのクラスを作成する。

app1/forms.py

```python
class PredictForm(forms.Form):
    input1 = forms.IntegerField(
        label='入力１',
        required=True,
    )

    input2 = forms.IntegerField(
        label='入力２',
        required=True,
    )
    
    input3 = forms.IntegerField(
        label='入力３',
        required=True,
    )
    
    input4 = forms.IntegerField(
        label='入力４',
        required=True,
    )
    
    input5 = forms.IntegerField(
        label='入力５',
        required=True,
    )
    
    input6 = forms.IntegerField(
        label='入力６',
        required=True,
    )
    
    input7 = forms.IntegerField(
        label='入力７',
        required=True,
    )
    
    input8 = forms.IntegerField(
        label='入力８',
        required=True,
    )
    
    input9 = forms.IntegerField(
        label='入力９',
        required=True,
    )
    
    input10 = forms.IntegerField(
        label='入力１０',
        required=True,
    )
    
    input11 = forms.IntegerField(
        label='入力１１',
        required=True,
    )
```

#####View関数の作成
XGBoostモデルをロードし、予測する。

```python
import numpy as np  
import xgboost as xgb  

def predict(request):
    model = xgb.XGBRegressor()
    model.load_model('./app1/src/xgb.model')

    if request.method == 'POST':
        form = forms.PredictForm(request.POST, request.FILES)

        if form.is_valid():
            input1 = form.cleaned_data['input1']
            input2 = form.cleaned_data['input2']
            input3 = form.cleaned_data['input3']
            input4 = form.cleaned_data['input4']
            input5 = form.cleaned_data['input5']
            input6 = form.cleaned_data['input6']
            input7 = form.cleaned_data['input7']
            input8 = form.cleaned_data['input8']
            input9 = form.cleaned_data['input9']
            input10 = form.cleaned_data['input10']
            input11 = form.cleaned_data['input11']

            inputs = np.array([input1, input2, input3, input4, input5,
                               input6, input7, input8, input9, input10, input11])
            inputs = np.expand_dims(inputs, axis=0)

            pred = model.predict(inputs)[0]

            d = {
                'prediction': pred,
            }

            return render(request, 'app1/predict_output.html', d)

        else:
            return HttpResponse('invalid form')

    else:
        form = forms.PredictForm()

    d = {
            'form': form
    }

    return render(request, 'app1/predict_input.html', d)
```


#####テンプレート (predict_input.html) の作成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/27485489-c2e4-9d3b-9ea1-85b3c07e2cb4.png)

templates/app1/predict_input.html

```html
{% extends "app1/base.html" %}

{% block body %}
  <form method="post" action="">{% csrf_token %}
    {{ form.input1.label }}：
    {{ form.input1 }}
    <br>
    {{ form.input2.label }}：
    {{ form.input2 }}
     <br>
    {{ form.input3.label }}：
    {{ form.input3 }}
     <br>
    {{ form.input4.label }}：
    {{ form.input4 }}
     <br>
    {{ form.input5.label }}：
    {{ form.input5 }}
     <br>
    {{ form.input6.label }}：
    {{ form.input6 }}
     <br>
    {{ form.input7.label }}：
    {{ form.input7 }}
     <br>
    {{ form.input8.label }}：
    {{ form.input8 }}
     <br>
    {{ form.input9.label }}：
    {{ form.input9 }}
     <br>
    {{ form.input10.label }}：
    {{ form.input10 }}
     <br>
    {{ form.input11.label }}：
    {{ form.input11 }}
    <br>
    <br>
    <input type="submit" value="送信" />
   </form>
{% endblock %}
```

#####テンプレート (predict_output.html) の作成

templates/app1/predict_output.html

```html
{% extends "app1/base.html" %}

{% block body %}
  <div>
    出力 :  {{prediction}}
  </div>
  <br>
  <div>
    <a href="{% url 'app1:app1_predict' %}">戻る</a><br>
  </div>
{% endblock %}
```

#####URLパターンの設定

app1/urls.py

```python
urlpatterns = [
    path('hello/', views.hello_world, name='app1_hello_world'),
    path('template/', views.hello_template, name='app1_hello_template'),
    path('forms/', views.hello_forms, name='app1_hello_forms'),
    path('predict/', views.predict, name='app1_predict'),  # 追加
]  
```

#####動作確認
入力画面

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/94697e09-aa63-88b3-5910-70d4faa89efd.png)

送信ボタンを押すと、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/37884470-9d8a-b3f4-a350-192e29e9693d.png)