【さくらVPS】【Python】Django で Web アプリを作る(ToDoアプリ編)【Part.10】

今回は今まで作成した Web アプリケーションを元に「ToDo」アプリを作成します。

何度も繰り返しアプリを作成することで「型」が分かってきます。

 

以下、今までの作業です。

【さくらVPS】【Python】Django で Web アプリを作る【Part.1】

 

【さくらVPS】【Python】Django で Web アプリを作る(Let's Encrypt SSL証明書設定)【Part.2】

 

【さくらVPS】【Python】Django で Web アプリを作る(Djangoインストール&設定)【Part.3】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ構築編)【Part.4】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ構築編)【Part.5】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ設定編)【Part.6】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ構築編)【Part.7】

 

【さくらVPS】【Python】Django で Web アプリを作る(メッセージ登録&表示アプリ編)【Part.8】

 

【さくらVPS】【Python】Django で Web アプリを作る(カスタマイズ編)【Part.9】

 

 

Webアプリを作る場合はレンタルサーバーより「VPS」の方が自由度が高いのでお勧めです。

ちなみに、「さくらのVPS」は価格が安くてスペックがいいです。

 

 

 

さくらのVPSのスペックです。

[test@SAKURA_VPS ~]$ cat /proc/cpuinfo | grep processor
processor       : 0
[test@SAKURA_VPS ~]$ cat /proc/meminfo | grep MemTotal
MemTotal:         500208 kB

 

月額    : 685円~

ディスク: SSD 20GB

CPU     : Intel Xeon CPU E5-2650v2 @ 2.60GHz 1個

メモリ  : 512MB

【さくらVPS】【Python】Django で Web アプリを作る(カスタマイズ編)【Part.9】

 

 

前回まで作成した Web アプリ

前回まで作成した Web アプリは、下図のようにメッセージを入力して「送信」ボタンをクリックすると上から追加され、空文字を入力しても「None」の文字は追加されない機能でした。

 

今回はこの Web アプリをカスタマイズして「ToDo」アプリを作成します。

 

 

 

 

ToDoアプリ作成

まず初めに作業をする前の事前準備をします。

ToDoアプリの簡単な設計

簡単でもいいので、箇条書きでもいいので最初に設計をします。

ToDoアプリは、

  • メッセージを投稿できる
  • 最新のメッセージを上から順に表示させる
  • 「削除」ボタンを表示して、メッセージを選択して「削除」ボタンをクリックするとメッセージが削除される

というアプリにします。

仮想環境に切り替える

今回も Python 仮想環境で行います。

初めに仮想環境に切り替えます。

[test@SAKURA_VPS ~]$ ls
django  scraping      テンプレート  ドキュメント  音楽  公開
pyenv   ダウンロード  デスクトップ  ビデオ        画像
[test@SAKURA_VPS ~]$ source pyenv/bin/activate ← 仮想環境に切り替えます。
(pyenv) [test@SAKURA_VPS ~ ]$ ← (pyenv)が表示され、仮想環境に切り替わったことが分かります。

 

 

ToDoプロジェクトを作成する

ToDo プロジェクトを作成します。

(pyenv) [test@SAKURA_VPS pyenv]$ pwd
/home/test/pyenv
(pyenv) [test@SAKURA_VPS pyenv]$ django-admin startproject todo ← todoプロジェクトを作成します。
(pyenv) [test@SAKURA_VPS pyenv]$ cd todo/
(pyenv) [test@SAKURA_VPS todo]$ python manage.py startapp todo_app ← Web アプリを作成します。
(pyenv) [test@SAKURA_VPS todo]$ python manage.py migrate ← マイグレーションします。
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, 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 sessions.0001_initial... OK
(pyenv) [test@SAKURA_VPS todo]$

 

 

 

 

settings.pyファイルを編集する

settings.pyファイルを編集します。

何のために編集するかと言うと

  • アプリケーション(todo_app)の登録
  • 日本語環境の設定
  • タイムゾーンの設定
  • style.cssや画像ファイルの場所設定

をしています。

(pyenv) [test@SAKURA_VPS todo]$ pwd
/home/test/pyenv/todo/todo
(pyenv) [test@SAKURA_VPS todo]$ vi settings.py
"""
Django settings for todo project.

Generated by 'django-admin startproject' using Django 1.11.7.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '9@)yi&kb6xxxxxxxxxxxxxxxxxxxxxxxm99&oq'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

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

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'todo.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'todo.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

#LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ja'

#TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

 

 

(アプリケーション)todo_app/urls.pyの新規作成

urls.py で URL Dispatcher の設定をします。

第一引数で、正規表現も文字列を指定し、第二引数で「ビュー関数」を指定します。

その他はオプションで、例えば「name='message_app_index'」は、組合せ名をオプションとして設定しています。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ vi urls.py ← 新規作成します。
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.todo_app_index, name='todo_app_index'),
]

 

 

(プロジェクト)todo/urls.pyの作成

こちらも同じく urls.py で URL Dispatcher の設定をします。

(pyenv) [test@SAKURA_VPS todo]$ pwd
/home/test/pyenv/todo/todo
(pyenv) [test@SAKURA_VPS todo]$ vi urls.py
"""todo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import include,url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^todo_app', include('todo_app.urls', namespace='todo_app')),
]

 

 

 

 

models.pyの編集

models.pyを編集します。

  • ToDo用のメッセージ
  • ToDoメッセージ

を投稿した時刻を表示する設定をしています。

(pyenv) [test@SAKURA_VPS message_app]$ pwd

/home/test/pyenv/todo/todo_app

(pyenv) [test@SAKURA_VPS todo_app]$ vi models.py
from django.db import models

# Create your models here.

class Todo_board(models.Model):
    new_message = models.CharField(max_length=200,)
    created_at = models.DateTimeField(auto_now_add=True,)

 

 

views.pyの編集

値が入っていない状態で、ブラウザをリロードしても「None」を表示させないためには「views.py」を以下のように修正します。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ vi views.py
from django.shortcuts import render, redirect

# Create your views here.
from .models import Todo_board

def todo_app_index(request):
    msg = request.GET.get('words')

    delete_text = request.POST.getlist('delete_text')

    if delete_text:
        Todo_board.objects.filter(id__in=delete_text).delete() ← 「id__in」とアンダーバーが2つ続いていることに注意です。

    if msg is None:
        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }
        return render(request, 'todo_app/index.html', contexts)

    else:
        message_data = Todo_board()
        message_data.new_message = msg
        message_data.save()

        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }

    return render(request, 'todo_app/index.html', contexts)

 

 

 

 

 

style.cssファイルと画像保存作成する

以下の作成をします。

  • /home/test/pyenv/todo/todo_app/static ディレクトリの作成
  • /home/test/pyenv/todo/todoe_app/static/css ディレクトリの作成
  • /home/test/pyenv/todo/todo_app/static/images ディレクトリの作成
  • /home/test/pyenv/todo/todo_app/static/css/style.css ファイルの作成

 

(pyenv) [test@SAKURA_VPS todo]$ pwd
/home/test/pyenv/todo/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ mkdir static
(pyenv) [test@SAKURA_VPS todo_app]$ cd static/
(pyenv) [test@SAKURA_VPS static]$ pwd
/home/test/pyenv/todo/todo_app/static
(pyenv) [test@SAKURA_VPS static]$ mkdir css
(pyenv) [test@SAKURA_VPS static]$ mkdir images
(pyenv) [test@SAKURA_VPS static]$ ls
css  images
(pyenv) [test@SAKURA_VPS static]$ cd css/
(pyenv) [test@SAKURA_VPS css]$ pwd
/home/test/pyenv/todo/todo_app/static/css
(pyenv) [test@SAKURA_VPS css]$ vi style.css
@charset "UTF-8";
p{
    font-size: 20px;
    color: #0000FF;
}

 

パスに注意しましょう。

私は「/home/test/pyenv/todo/todo_app/static/」ではなく「/home/test/pyenv/todo/todo/static/」に作ってしまい、ハマりました。

気を付ける点は、

  • templatesディレクトリ
  • staticディレクトリ

は同じディレクトリに作成するということです。

 

テンプレートの作成

初めに以下の3つのファイルを作成します。

  • /home/test/pyenv/message_site/message_app/templates/message_app/base.html
  • /home/test/pyenv/message_site/message_app/templates/message_app/index.html
  • /home/test/pyenv/message_site/message_app/templates/message_app/result.html

 

(pyenv) [test@SAKURA_VPS message_app]$ pwd
/home/test/pyenv/todo/todo_app

(pyenv) [test@SAKURA_VPS todo_app]$ ls
__init__.py    apps.py       models.py    tests.py      views.py
admin.py       migrations    urls.py      
(pyenv) [test@SAKURA_VPS todo_app]$ mkdir templates
(pyenv) [test@SAKURA_VPS todo_app]$ cd templates/
(pyenv) [test@SAKURA_VPS templates]$ pwd
/home/test/pyenv/todo/todo_app/templates
(pyenv) [test@SAKURA_VPS templates]$ mkdir message_app
(pyenv) [test@SAKURA_VPS templates]$ cd message_app/
(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app/templates/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ touch base.html
(pyenv) [test@SAKURA_VPS todo_app]$ touch index.html
(pyenv) [test@SAKURA_VPS todo_app]$ touch result.html
(pyenv) [test@SAKURA_VPS todo_app]$ ls
base.html    index.html    result.html

 

 

 

result.htmlの編集

result.htmlを編集します。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app/templates/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ ls
base.html    index.html      result.html

(pyenv) [test@SAKURA_VPS todo_app]$ vi result.html
{% block body %}
    {% if result_list %}
        {% for i in result_list %}
            <p><input type="checkbox" name="delete_text" value="{{i.id}}">{{i.new_message}}:{{i.created_at}}</p>

        {% endfor %}
    {% endif %}
{% endblock %}

 

 

 

 

index.htmlの編集

index.htmlを編集します。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app/templates/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ vi index.html
{% extends 'todo_app/base.html' %}
{% block body %}
    <form action="{% url 'todo_app:todo_app_index' %}" method="get">
        
        <input type="submit" value="送信">
    </form>    

    <form action="{% url 'todo_app:todo_app_index'%}" method="post">{% csrf_token %}
        {% include "todo_app/result.html" %}
        <input type="submit" value="削除">
    </form>
{% endblock %}

 

 

 

base.htmlの編集

base.htmlを編集します。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app/templates/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ vi base.html
<!DOCTYPE html>
<html lang="ja">

<head>
<meta charset="UTF=8">
{% load static %}
    <link rel="stylesheet" href="{% static 'css/style.css' %}">

</head>

<body>
    {% block body %}
    {% endblock %}

</body>

</html>

 

 

 

開発サーバーの起動

ここまでできたら開発サーバーを起動します。

(pyenv) [test@SAKURA_VPS todo]$ pwd
/home/test/pyenv/todo

(pyenv) [test@SAKURA_VPS todo]$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
November 11, 2017 - 20:23:27
Django version 1.11.7, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

 

 

 

動作確認

プログラムの動作確認をします。

メッセージ追加テスト

以下のように「メッセージ」欄に文字列を入力して「送信」ボタンをクリックすると、下図のように上から順に追加されていきます。

 

削除テスト

削除テストをしてみます。

 

以下のようにメッセージが削除されています。

 

 

 

 

 

 

エラー集

本当はエラーが出ないのが一番いいのですが、どうしてもエラーが出てしまいます。

そんな時も諦めずにじっくりと原因を調べましょう。

 

Page not found (404)

これは明らかにURLが間違っています。

タイプミスが原因の場合が多いです。

 

 

空白の場合

何らエラーメッセージが出ないパターンです。

 

しかし、開発サーバーを起動した端末には以下のようにログが出力されているはずです。

[12/Nov/2017 09:13:54] "GET /todo_app HTTP/1.1" 200 175
Traceback (most recent call last):
  File "/usr/lib64/python3.6/wsgiref/handlers.py", line 137, in run
    self.result = application(self.environ, self.start_response)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/handlers.py", line 64, in __call__
    return super(StaticFilesHandler, self).__call__(environ, start_response)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/core/handlers/wsgi.py", line 157, in __call__
    response = self.get_response(request)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/handlers.py", line 54, in get_response
    return self.serve(request)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/handlers.py", line 47, in serve
    return serve(request, self.file_path(request.path), insecure=True)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/views.py", line 34, in serve
    absolute_path = finders.find(normalized_path)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/finders.py", line 249, in find
    for finder in get_finders():
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/finders.py", line 264, in get_finders
    yield get_finder(finder_path)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/finders.py", line 277, in get_finder
    return Finder()
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/contrib/staticfiles/finders.py", line 57, in __init__
    "Your STATICFILES_DIRS setting is not a tuple or list; "
django.core.exceptions.ImproperlyConfigured: Your STATICFILES_DIRS setting is not a tuple or list; perhaps you forgot a trailing comma?
[12/Nov/2017 09:13:55] "GET /static/css/style.css HTTP/1.1" 500 59

 

以下を修正しました。

【修正前】

(pyenv) [test@SAKURA_VPS todo]$ pwd
/home/test/pyenv/todo/todo
(pyenv) [test@SAKURA_VPS todo]$ vi settings.py

 

~ 省略 ~

 

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static')
)

 

↓ 以下のように修正しました。

 

【修正後】

(pyenv) [test@SAKURA_VPS todo]$ pwd
/home/test/pyenv/todo/todo
(pyenv) [test@SAKURA_VPS todo]$ vi settings.py

 

~ 省略 ~

 

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'), ← カンマを付けました。
)

 

 

 

 

しかし、まだ何かが足りなさそうです。

[12/Nov/2017 09:13:55] "GET /static/css/style.css HTTP/1.1" 500 59
Performing system checks...

System check identified no issues (0 silenced).
November 12, 2017 - 09:36:16
Django version 1.11.7, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[12/Nov/2017 09:36:31] "GET /todo_app HTTP/1.1" 200 175
[12/Nov/2017 09:36:32] "GET /static/css/style.css HTTP/1.1" 404 1652
[12/Nov/2017 09:39:14] "GET /todo_app HTTP/1.1" 200 175
[12/Nov/2017 09:39:14] "GET /static/css/style.css HTTP/1.1" 404 1652
[12/Nov/2017 09:39:15] "GET /todo_app HTTP/1.1" 200 175
[12/Nov/2017 09:39:15] "GET /static/css/style.css HTTP/1.1" 404 1652

 

「HTTP 404」と表示されているので「ページが見つかりません」という意味になります。

プログラムが間違えていそうです。

 

もう1つミスを発見。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app

(pyenv) [test@SAKURA_VPS todo_app]$ vi views.py

from django.shortcuts import render, redirect

# Create your views here.
from .models import Todo_board

def todo_app_index(request):
    msg = request.GET.get('words')

    delete_text = request.POST.getlist('delete_text')

    if delete_text:
        Todo_board.objects.filter(id_in=delete_text).delete()

    if msg is None:
        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }
        return render(request, 'todo_app/index.html', contexts)

    else:
        message_data = Todo_board()
        message_data.new_message = msg
        message_data.save()

        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'reqult_list': data_list, ← スペルミス
        }

    return render(request, 'todo_app/index.html', contexts)

 

↓ 以下のように修正しました。

 

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ vi views.py
from django.shortcuts import render, redirect

# Create your views here.
from .models import Todo_board

def todo_app_index(request):
    msg = request.GET.get('words')

    delete_text = request.POST.getlist('delete_text')

    if delete_text:
        Todo_board.objects.filter(id_in=delete_text).delete()

    if msg is None:
        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }
        return render(request, 'todo_app/index.html', contexts)

    else:
        message_data = Todo_board()
        message_data.new_message = msg
        message_data.save()

        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }

    return render(request, 'todo_app/index.html', contexts)
(pyenv) [test@SAKURA_VPS todo_app]$

 

 

しかし、まだまだ現象は変わらずです。。

Performing system checks...

System check identified no issues (0 silenced).
November 12, 2017 - 10:00:22
Django version 1.11.7, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[12/Nov/2017 10:00:31] "GET /todo_app HTTP/1.1" 200 175
[12/Nov/2017 10:00:31] "GET /static/css/style.css HTTP/1.1" 404 1652

 

 

ここで、そもそも「"GET /static/css/style.css HTTP/1.1" 404 1652」が表示されるということはパスが間違っているはずと考えて調べてみたところ、「static」の配置が間違っていました。

「static」ディレクトリは「templates」ディレクトリと同じ階層に置く必要がありますが、間違ったディレクトリに配置していました。

 

  • ミス → /home/test/pyenv/todo/todo 配下に「static」ディレクトリを配置する
  • 正しくは → /home/test/pyenv/todo/todo_app 配下に「static」ディレクトリを配置する

 

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app
(pyenv) [test@SAKURA_VPS todo_app]$ ls
__init__.py  admin.py  migrations  templates  urls.py  
__pycache__  apps.py   models.py   static     tests.py   views.py
(pyenv) [test@SAKURA_VPS todo_app]$

 

 

再度マイグレーションをしてみます。

^C(pyenv) [test@SAKURA_VPS todo]$ ← 「Ctrl」+「C」で一旦開発サーバーを停止します。
(pyenv) [test@SAKURA_VPS todo]$
(pyenv) [test@SAKURA_VPS todo]$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  No migrations to apply.
  Your models have changes that are not yet reflected in a migration, and so won't be applied.
  Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them. ← モデルを変更した場合は、初めに「makemigrations」を実行するように言われました。
(pyenv) [test@SAKURA_VPS todo]$ python manage.py makemigrations
Migrations for 'todo_app':
  todo_app/migrations/0001_initial.py
    - Create model Todo_board
(pyenv) [test@SAKURA_VPS todo]$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, todo_app
Running migrations:
  Applying todo_app.0001_initial... OK
(pyenv) [test@SAKURA_VPS todo]$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
November 12, 2017 - 10:25:48
Django version 1.11.7, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[12/Nov/2017 10:25:54] "GET /todo_app HTTP/1.1" 200 175
[12/Nov/2017 10:26:02] "GET /todo_app HTTP/1.1" 200 175
[12/Nov/2017 10:26:02] "GET /static/css/style.css HTTP/1.1" 200 64 ← ゲットは出来ているようです。

 

 

しかし、画面は空白のままです。

まだ何かが間違っているようです。

 

【原因】

「index.html」の記述ミス(スペルミス)でした。

そもそも「index.html」の記述が間違っていれば、何も表示されません。

 

 

Cannot resolve keyword 'id_in' into field. Choices are: created_at, id, new_message

削除のチェックを入れて「削除」ボタンをクリックします。

 

以下のように「FieldError at /todo_app Cannnot resolve keyword 'id_in' into field. Choices are: created_at, id, new_message」のエラーが出力されました。

これもプログラムのスペルミスのような気がします。

 

開発サーバーのコンソールには以下のエラーメッセージが出力されています。

「id_in」のスペルが間違っているのでしょうか?

Internal Server Error: /todo_app
Traceback (most recent call last):
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/test/pyenv/todo/todo_app/views.py", line 12, in todo_app_index
    Todo_board.objects.filter(id_in=delete_text).delete()
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/query.py", line 784, in filter
    return self._filter_or_exclude(False, *args, **kwargs)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/query.py", line 802, in _filter_or_exclude
    clone.query.add_q(Q(*args, **kwargs))
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/sql/query.py", line 1250, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/sql/query.py", line 1276, in _add_q
    allow_joins=allow_joins, split_subq=split_subq,
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/sql/query.py", line 1154, in build_filter
    lookups, parts, reffed_expression = self.solve_lookup_type(arg)
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/sql/query.py", line 1034, in solve_lookup_type
    _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
  File "/home/test/pyenv/lib64/python3.6/site-packages/django/db/models/sql/query.py", line 1352, in names_to_path
    "Choices are: %s" % (name, ", ".join(available)))
django.core.exceptions.FieldError: Cannot resolve keyword 'id_in' into field. Choices are: created_at, id, new_message
[12/Nov/2017 11:28:41] "POST /todo_app HTTP/1.1" 500 104760

 

views.pyを再度確認します。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app

(pyenv) [test@SAKURA_VPS todo_app]$ cat views.py
from django.shortcuts import render, redirect

# Create your views here.
from .models import Todo_board

def todo_app_index(request):
    msg = request.GET.get('words')

    delete_text = request.POST.getlist('delete_text')

    if delete_text:
        Todo_board.objects.filter(id_in=delete_text).delete() ← 「id_in」が間違えでした。

    if msg is None:
        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }
        return render(request, 'todo_app/index.html', contexts)

    else:
        message_data = Todo_board()
        message_data.new_message = msg
        message_data.save()

        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }

    return render(request, 'todo_app/index.html', contexts)
(pyenv) [test@SAKURA_VPS todo_app]$

 

views.pyを修正します。

  • 間違え ← id_in (アンダーバーが1つしかありません)
  • 正解  ← id__in(アンダーバーが2つあります)

これは全く気が付きませんでした。

(pyenv) [test@SAKURA_VPS todo_app]$ pwd
/home/test/pyenv/todo/todo_app

(pyenv) [test@SAKURA_VPS todo_app]$ vi views.py
from django.shortcuts import render, redirect

# Create your views here.
from .models import Todo_board

def todo_app_index(request):
    msg = request.GET.get('words')

    delete_text = request.POST.getlist('delete_text')

    if delete_text:
        Todo_board.objects.filter(id__in=delete_text).delete()

    if msg is None:
        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }
        return render(request, 'todo_app/index.html', contexts)

    else:
        message_data = Todo_board()
        message_data.new_message = msg
        message_data.save()

        data_list = Todo_board.objects.order_by('-id')
        contexts = {
            'result_list': data_list,
        }

    return render(request, 'todo_app/index.html', contexts)
(pyenv) [test@SAKURA_VPS todo_app]$

 

 

参考文献

今回構築した Django 環境の参考文献です。

Amazonの「Kindle Unlimited」で購入しました。

淵上喜弘著 「1日で理解するDjango超基礎入門」です。

書物としてまとまった Django の本がほとんどない中で、非常に役に立ちました。

本著の内容は、詳しい解説と言うよりはどんどん Web アプリを作っていくスタイルです。

そのため、文法など細かい解説が欲しい方には物足りなく感じるかもしれませんが、作って動かしてみて理解するスタイルが合う方には有用だと思います。

1日で理解するDjango超基礎入門

 

今までの連載

【さくらVPS】【Python】Django で Web アプリを作る【Part.1】

 

【さくらVPS】【Python】Django で Web アプリを作る(Let's Encrypt SSL証明書設定)【Part.2】

 

【さくらVPS】【Python】Django で Web アプリを作る(Djangoインストール&設定)【Part.3】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ構築編)【Part.4】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ構築編)【Part.5】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ設定編)【Part.6】

 

【さくらVPS】【Python】Django で Web アプリを作る(Webアプリ構築編)【Part.7】

 

【さくらVPS】【Python】Django で Web アプリを作る(メッセージ登録&表示アプリ編)【Part.8】

 

【さくらVPS】【Python】Django で Web アプリを作る(カスタマイズ編)【Part.9】

 

 

感想

基本が分かっていないと結構ハマります。

まだまだ Django の仕組みを基本から勉強する必要があると痛感しました。

しかし自分の作りたい Web アプリを作れるようになるまで Django を勉強しようと思います。

 

 

Posted by 100%レンタルサーバーを使いこなすサイト管理人

コメントを残す

メールアドレスが公開されることはありません。