PythonMania

普段はロボットとAIを組み合わせて色々作ってます。Python関係以外も色々投稿していくと思います。

【Djnago】Dropifyを使ってフォームをカッコよくカスタマイズ

f:id:mizuhiki0111:20190430175940p:plain



DjangoのformsAPI を使えば簡単にフォームを実装できるんですが、何も弄らない状態だととてもシンプルなデザインになってしまいます。

CSSやBootstrapを使ってデザインを変更することもできますが、今回は「Dropify」を使ってドラッグアンドドロップでファイルをアップロードできるフォームを作成してみたいと思います。


Dropify
jeremyfagis.github.io





使い方は簡単で、テンプレートでDropify関連のjsやcssを読み込むだけで実装できます。


CSSの読み込み

    <link rel='stylesheet' href='http://cdn.rawgit.com/JeremyFagis/dropify/master/dist/css/dropify.css' />

javascriptの読み込み

  <script src='http://cdn.rawgit.com/JeremyFagis/dropify/master/dist/js/dropify.js'></script>


初期化の実行

<script>
$(function(){
  $('.dropify').dropify();
})
</script>


あとはgithubのページから「dist/fonts」フォルダをダウンロードしてきてテンプレートで読み込めば完了です。

github.com






使用するときはinputタグを以下の様に変更します。

  <input type="file" class="dropify" data-default-file="Drag and Drop Your FIle Here" name="uploadfile" />
  <button type="submit" class="btn">Send</button>


これでカスタマイズされたフォームが表示されると思います。




ちなみに今回の実装ではDjangoのフォームは使用していないので、python側でPOSTリクエストを受け取る場合はviews.pyを以下の様に記述します。

※今回使用しているmodels.pyは過去記事と同様なので、そちらをご参照ください。

www.pythonmania.work



    photo = Photo()
    photo.image = request.FILES.get("uploadfile")
    photo.save()


【Django】フォームを使ってフォルダごとファイルをアップロードしてみる

f:id:mizuhiki0111:20190430175940p:plain




通常は単一のファイルをアップロードするImageFieldやFileFieldですが、今回はこれらのフォームを使ってフォルダの中身を一括してアップロードしてみたいと思います。


※今回の実装は「HTMLInputElement.webkitDirectory」という機能を使用して作られています。

以下のサイトに記載の通り、webkitDirectoryは標準機能ではないため環境によってはうまく動作しない場合があります。

なので本番環境等での使用はオススメしません。。
developer.mozilla.org








①models.py

models.pyは単一ファイルのアップロード機能を作る場合と変わりません。

from django.db import models


class FolderUpload(models.Model):
    file = models.ImageField('画像ファイル')

    def __str__(self):
        return self.file.url




②forms.py

from django import forms

class FileFieldForm(forms.Form):
    file_field = forms.ImageField(widget=forms.ClearableFileInput(attrs=
        {'multiple': True, 'webkitdirectory': True, 'directory': True}))


フォームの作成ではwidgetを使用し、「webkitdirectory': True, 'directory': True」を指定しています。




③views.py


views.pyです。FormViewを使用してクラスを定義しています。


class FolderUploadView(FormView):
    form_class =  FolderUploadForm
    template_name = 'myapp/upload.html'
    success_url = 'myapp/result.html'

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        files = request.FILES.getlist('file_field')
        if form.is_valid():
            for file in files:
                new_file = FolderUpload(file=file)
                new_file.save()
            return self.form_valid(form)
        else:
            return self.form_invalid(form)



④urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
    url('upload/', views.FolderUploadView.as_view(), name='upload'),
]

⑤upload.html

<table>
  <form action="{% url 'upload' %}"  method="POST" enctype="multipart/form-data">
  {% csrf_token %}
  {{ form.as_p }}
    <input type="submit" id="upload_files" name="upload_files" value="submit"  webkitdirectory directory />
  </form>
</table>


inputタグのところで「webkitdirectory directory /」と記載しておきます。





フォルダをアップロードすると、フォルダ内のファイルが一括してmediaディレクトリに保存されていると思います。



GitHubにログインできなくなった、、

f:id:mizuhiki0111:20190702143538j:plain



GitHubのログイン時に二段階認証を設定していたのですが、メールアドレスを変更した際にGitHubの設定を変更するのを忘れてしまいログインできなくなってしまいました。。。




取り急ぎ使用する予定があったので、ひとまず新しいアカウントを作成しpushしようとしたところ

「error: failed to push some refs to~」のエラーが出現。


色々調べたところ

git pull

からの

git fetch

からの

git merge origin/master

で解決しました。。(泣


【Django】Google App EngineにDjangoアプリをデプロイしてみる【追記】

f:id:mizuhiki0111:20190430175940p:plain





前回の記事でDjangoアプリをGoogla App Engineにデプロイする流れをまとめましたが、前回の記事では色々と不十分なところがあったので

追記します。すみません。。。笑



前回の記事が以下になりますが、基本的には今回の記事を参考にしてもらえれば幸いです。

www.pythonmania.work





①Python環境の作成


公式HPよりPythonインストーラをダウンロードし、インストールします。
インストールする際には必ず [PATH に Python を追加]をチェックしてください。

www.python.org


今回はPython3系をインストールしました。


インストールが完了したら、コンソールを立ち上げ仮想環境構築用のモジュールをインストールします。

pip install --upgrade virtualenv

次に仮想環境を作成します。

virtualenv --python "python.exeへのフルパス" 仮想環境名

仮想環境が作成されたら、作成した仮想環境を有効化します。

\仮想環境名\Scripts\activate

ここまででPython環境・仮想環境の構築が完了しました。この作業を行うことで、ほかのプロジェクトに影響を受けずにアプリ開発を行うことができます。









②Cloud SDKのインストール

公式HPよりCloud SDKをインストールしてきます。


cloud.google.com



またPython用Cloud クライアントライブラリもインストールしておきます。

pip install --upgrade google-cloud-storage

また以下のコマンドを使ってクラウドのインスタンスを初期化しておきます

gcloud init

上記コマンドを入力すると色々表示されますが、GCPで作成したプロジェクトを選択し、使用するアカウントを選べばOKだと思います。



③Cloud SQL Proxyのダウンロード

以下のURLを右クリックして「名前つけてリンク先を保存」します。

名前は「cloud_sql_proxy」にしておいてください

https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe




④Cloud SQL インスタンスの作成



以下のリンク参照しながらCloud SQLの第2世代インスタンスを作成していきます

cloud.google.com




1. インスタンス作成をクリック

2.「MySQL」を選択して「次へ」

3.「第2世代を選択」をクリック

4. 名前・パスワードをクリック

5. インスタンスのリージョン設定(プロジェクトと一緒でOK,東京なら「asia-northeast1」

6. ゾーンはそのままでOK




次にコンソールでの作業に移ります

コンソールで以下を実行

gcloud sql instances describe [YOUR_INSTANCE_NAME]


出力された [CONNECTION_NAME] をメモしておく

[CONNECTION_NAME] の値は、[PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME] の形式になっています






次にCloudSQLProxyをインストールしたディレクトリに移動し

cloud_sql_proxy.exe -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:3306


を実行


[YOUR_INSTANCE_CONNECTION_NAME]は先程メモした[CONNECTION_NAME]の値に書き換え

※An attempt was made to access a socket in a way forbidden by its access permissions.みたいなエラーは、3306のポートへ外部からアクセスできないために起こります。
 使用するポート番号(3306)を開放する必要があります。



「Ready for new connections」と出てきたら、このコンソールはローカルでアプリのテストが完了するまでそのままにしておく

→ここからはもう一つコンソールを開いてそちらで作業していきます


⑤Djangoアプリの作成


別のコンソールを開いたらまず仮想環境の有効化を行います。

.\環境名\Scripts\activate

Djangoのインストール

pip install django==2.1

※Djnago2.2~ではpymysqlをインストールした際にエラーが発生してしましました。
 Djjango2.1系をインストールしてください


その他必要なライブラリのインストール

pip install django-storages
pip install pymysql


プロジェクトの作成

django-admin startproject プロジェクト名

アプリの作成

cd プロジェクト名
python manage.py startapp アプリ名


アプリ作成まで完了したら

python manage.py runserver

で試しに起動してみます。






⑥init.pyの編集

プロジェクトのinit.pyに以下を追記します。

#init.py
import pymysql  # 追記

pymysql.install_as_MySQLdb() #追記


⑦app.yamlの作成


manage.pyと同じ階層に「app.yaml」を作成し内容を以下の様に作成します。

runtime: python37
entrypoint: gunicorn -b :$PORT プロジェクト名.wsgi:application

handlers:
- url: /static
  static_dir: static/
- url: /.*
  script: auto


このファイルはAppEngineの構成ファイルを設定するもので、参照するwsgiファイルやstaticディレクトリなどを記載しておきます。


「プロジェクト名」のところはDjangoで作成したプロジェクトの名前に変更しておいてください。







⑧サービスアカウント・ユーザー・データベースの作成


今度はGCPのサイト上で操作していきます。


まずAPIにアクセスするためのサービスアカウントを作成します。




メニューの「APIとサービス」「認証情報の作成」をクリックします。


次に青色の「認証情報を作成」ボタンをクリックし、「サービスアカウントの作成」をクリックします。


「新しいサービスアカウント」→Jsonを選択し、作成をするとサービスアカウントキー情報が記載された

JSONファイルがダウンロードできると思います。


※なお「役割」を選択するプルダウンが表示された場合には「ストレージ」→「ストレージ管理者」として置いてください。
そうしないと後でDBにアクセスするときにエラーが発生してしまいます。



これをmanage.pyと同じディレクトリに保存しておいてください。



次に、先ほど作成したCloudSQLの第二世代インスタンスにユーザーとデータベースを作成していきます。



まずメニューから「SQL」を選択します。

インスタンスの名前をクリックし、「ユーザー」タブをクリックします。


「ユーザーアカウントの作成」から「ユーザー名」「パスワード」を入力し、新規ユーザーを作成してください。




同様にデータべースも作成していきます。



「データベース」タブに移行し、「データベースを作成」ボタンから新規データベースを作成してください。



⑨バケットの作成

バケットはクラウド上に画像などのファイルを保存しておく場所になります。


今回の場合はDjangoアプリのstaticディレクトリ内のファイルややmediaディレクトリなどをここで管理する形となります。


メニューから「Storage」を選択して、画面上部の「バケットを作成」から新規バケットを作成します。


ここでも役割を選択するプルダウンが表示された場合にはStorage管理者としておいてください。






⑩setting.pyの編集

setting.pyを順番に編集していきます。


ライブラリのインポート

from google.cloud import storage

INSTALLED_APPSの追加

    'mysite',
    'storages',  #追加
    'bootstrap4',
    'django_cleanup',
    'widget_tweaks',
    'bootstrap_datepicker_plus',
    'accounts.apps.AccountsConfig',


データベース設定の記載部分

if os.getenv('GAE_APPLICATION', None):
    # Running on production App Engine, so connect to Google Cloud SQL using
    # the unix socket at /cloudsql/<your-cloudsql-connection string>
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': '/cloudsql/"[YOUR_INSTANCE_CONNECTION_NAME]"',
            'USER': 'データベースのユーザー名",
            'PASSWORD': 'データベースのパスワード',
            'NAME': '作成したデータベース名',
        }
    }
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': 'localhost',
            'PORT': '3306',
            'NAME': 'データベース名(ローカル)',
            'USER': 'root',
            'PASSWORD': 'データベースのパスワード',
        }
    }

データベースの設定記載部分は、上段にクラウドSQLの情報、下段にローカルのデータベースの情報を記載しておきます。


その他バケットやサービスアカウントの設定などを記載していきます。

STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

ALLOWED_HOSTS = ["インスタンス名.appspot.com","127.0.0.1",'localhost']

from google.oauth2 import service_account
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
    'サービスアカウントキー(jsonファイル)へのパス(同階層であればファイル名を書けばOK)'
)

DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'
STATICFILES_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'
GS_BUCKET_NAME = '⑨で作成したバケット名'
GS_PROJECT_ID = 'プロジェクトID'


これでsetting.pyの変更は完了です。















無事に起動ができたら、以下のコマンドでGAEへデプロイすることができます。

requirements.txtの作成

pip freeze > requirements.txt

※requirements.txtを作成したら、追加で「gunicorn==19.9.0」を記載しておきます。

gcloud app deploy


【Django】Google App EngineにDjangoアプリをデプロイしてみる

f:id:mizuhiki0111:20190430175940p:plain




今回はGoogle App Engine上にDjangoで作成したアプリをデプロイするところまでをやってみたいと思います。







Google App Engineとは?

Google App Engine(以下GAE)とは作成したアプリを簡単に公開できるサービスで、いわゆる「PaaS(Platform as a Service)」に分類されます。

使用できる言語も増えてきており、Pythonも対応しています。



公式ページ
cloud.google.com





今回はDjangoでアプリまで作成し、GAE上にデプロイするところまでやってみます。



前提としてGoocle Cloud Platformのアカウント登録・新規プロジェクトの作成は済ませているものとします。





①Python環境の作成


公式HPよりPythonインストーラをダウンロードし、インストールします。
インストールする際には必ず [PATH に Python を追加]をチェックしてください。

www.python.org


今回はPython3系をインストールしました。


インストールが完了したら、コンソールを立ち上げ仮想環境構築用のモジュールをインストールします。

pip install --upgrade virtualenv

次に仮想環境を作成します。

virtualenv --python "python.exeへのフルパス" 仮想環境名

仮想環境が作成されたら、作成した仮想環境を有効化します。

\仮想環境名\Scripts\activate

ここまででPython環境・仮想環境の構築が完了しました。この作業を行うことで、ほかのプロジェクトに影響を受けずにアプリ開発を行うことができます。









②Cloud SDKのインストール

公式HPよりCloud SDKをインストールしてきます。


cloud.google.com



またPython用Cloud クライアントライブラリもインストールしておきます。

pip install --upgrade google-cloud-storage





③Cloud SQL Proxyのダウンロード

以下のURLを右クリックして「名前つけてリンク先を保存」します。

名前は「cloud_sql_proxy」にしておいてください

https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe




④Cloud SQL インスタンスの作成



以下のリンク参照しながらCloud SQLの第2世代インスタンスを作成していきます

cloud.google.com




1. インスタンス作成をクリック

2.「MySQL」を選択して「次へ」

3.「第2世代を選択」をクリック

4. 名前・パスワードをクリック

5. インスタンスのリージョン設定(プロジェクトと一緒でOK,東京なら「asia-northeast1」

6. ゾーンはそのままでOK




次にコンソールでの作業に移ります

コンソールで以下を実行

gcloud sql instances describe [YOUR_INSTANCE_NAME]


出力された [CONNECTION_NAME] をメモしておく

[CONNECTION_NAME] の値は、[PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME] の形式になっています






次にCloudSQLProxyをインストールしたディレクトリに移動し

cloud_sql_proxy.exe -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:3306


を実行


[YOUR_INSTANCE_CONNECTION_NAME]は先程メモした[CONNECTION_NAME]の値に書き換え

※An attempt was made to access a socket in a way forbidden by its access permissions.みたいなエラーが出たら3307に書き換えたらできるかも




「Ready for new connections」と出てきたら、このコンソールはローカルでアプリのテストが完了するまでそのままにしておく

→ここからはもう一つコンソールを開いてそちらで作業していきます


⑤Djangoアプリの作成


別のコンソールを開いたらまず仮想環境の有効化を行います。

.\環境名\Scripts\activate

Djangoのインストール

pip install django

プロジェクトの作成

django-admin startproject プロジェクト名

アプリの作成

cd プロジェクト名
python manage.py startapp アプリ名


アプリ作成まで完了したら

python manage.py runserver

で試しに起動してみます。



無事に起動ができたら、以下のコマンドでGAEへデプロイすることができます。

requirements.txtの作成

pip freeze > requirements.txt
gcloud app deploy


【Django】DjangoでMySQLを使ってみる

f:id:mizuhiki0111:20190430175940p:plain



Djangoには標準でSQLliteというデータベースが搭載されていて、migrateすればすぐに使うことができます。


ですが本格的なアプリ開発の場合、SQLliteではなく「MySQL」や「Oracle Database」といったものを使用するケースが多いと思います。



今回はMySQLをインストールし、Djangoのデータベースとして設定するところまでやってみたいと思います。




環境
Windows10 64bit
Anaconda3
Django2.1
python3.7




①MySQLのダウンロード・インストール


公式サイトからMySQL(Windows用)のインストーラをダウンロードしてきます。

公式サイト
dev.mysql.com




ダウンロードしてきたらインストーラを起動し、画面の表示に従って進めていきます。


基本的にNext・Executeで進めていけばOKですがいくつか注意点があるので記載しておきます。



①「One or more product reqquirements have not been satisfied」が出た場合

僕の場合、上記エラーが出て「Pythonがインストールされてないから公式サイトからダウンロードしてきてね」みたいな警告が出てきました。

でも実際にはAnacondaとPythonは入っているので、無視して「Yes」を押して先に進みました笑



②MySQL Serverの初期設定

インストールが完了すると、そのままサーバーの初期設定画面に進みます。

「Type and Networking」という画面が出てきたらConfig Typeなんかを選べるようになると思いますが、今回は練習用(開発用)のためそのまま(Development~)のまま次に進みます。


ポート番号の設定画面が表示されますが、デフォルトの「3306」がほかのアプリケーションで使用済の場合は変更してください。



次にアカウントの設定画面に進みます。


Accounts and Roles画面が表示されるので、rootアカウントのパスワードを設定します。


パスワードを入れたら画面下部のMySQL User Accountsの「Add User」ボタンから詳細を設定していきます。

ここでは「Username」・「password」を入力してください。





あとはNextボタンで最後まで進んでいけば完了です!



②パスの設定


インストールが完了したら、MySQLServerまでのパスを環境変数に設定します。

ぼくの場合は「"C:\Program Files\MySQL\MySQL Server 8.0\bin"」となりました。





③データベースの作成

DjangoでSQLliteを使用する際には特に意識しなかった作業ですが、MySQLを使う場合にはデータベースを事前にMySQLで作成した後にDjangoで読み込む必要があります。


コマンドプロンプト(もしくはAnaconda Prompt)を開き、以下の様に進めます。


①MySQLサービスの起動(既に起動している場合は飛ばしてOKです)

mysql> net start mysql80


②MySQLへの接続

mysql> mysql -u root -p

パスワードが求められるのでインストール時に設定したパスワードを入力してください


③データベースの作成

mysql> CREATE DATABASE testdb;

今回は"testdb"という名前のデータベースを作成します。


④テーブルの確認

mysql> USE testdb;
mysql> SHOW TABLES;

まだテーブルは作成していないので「Empty set」と表示されると思います。

これで無事にデータベースを作成することができました。

次に作成したデータベースをDjangoのプロジェクトに設定していきます。




④MySQLとDjangoの連携

まず最初にDjangoのバージョンの確認です。

今まではDjango2.2を使用してきましたが、Dango2.2でMySQLと接続しようとすると以下のようなエラーが発生します。

django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.


解決策としてDjangoのバージョンを2.2→2.1に変更する必要があります。


①PyMySQLのインストール

pip install pymysql


②manage.pyの編集

import os
import sys
import pymysql  # 追記

pymysql.install_as_MySQLdb()  # 追記

if __name__ == '__main__':


③settings.pyの編集

データベースに関する設定部分を以下の様に変更します

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'データベース名',
        'USER': 'ユーザー名',
        'PASSWORD': 'パスワード',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

「データベース名」・「ユーザー名」・「パスワード」はご自身の設定に合わせて変更してください。



僕の場合は
データベース名:testdb
ユーザー名:root
となります。


これでDjangoとMySQLを連携させることができました。


migrateしてテーブルを確認してみると、Djangoで作成されたテーブルが表示されると思います。


migrate

python manage.py migrate


テーブルの確認

mysql> USE testdb;
mysql> SHOW tables;



【Django】ModelFormを使ってフォーム処理をシンプルにする

f:id:mizuhiki0111:20190430175940p:plain

Djangoでフォームとデータベースを使用するとき、今まではmodels.pyとforms.pyに同じようなコードを書いて処理していました。




例えばフォームから「名前」・「年齢」・「メールアドレス」を送信し、それらをデータベースに保存する場合は


forms.py

from django import forms
from .models import Friend
class HelloForm(forms.Form):
    name = forms.CharField(label="Name")
    age = forms.IntegerField(label = "Age")
    mail = forms.EmailField(label = "Email")

models.py

class Friend(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField(default=0)
    mail = models.EmailField(max_length=200)


のように設定し、views.pyでは

    if (request.method == "POST"):
        #フォームクラスのインスタンス作成
        name = request.POST["name"]
        mail = request.POST["mail"]
        age = int(request.POST["age"])
        #保存した変数をもとにFriendクラスのインスタンスを生成
        friend = Friend(name = name,mail = mail,age = age)
        friend.save()
        #ローカルホスト/myappにリダイレクト
        return redirect(to = '/myapp')

のように、フォームから送信された情報を一つ一つ変数に格納し、そこからモデル(Friendクラス)のインスタンスを作成してレコードに追加していました。






これをDjangoのModelFormを使ってもっと簡潔に処理をしてみたいと思います。


ModelFormを使えばModelで定義したクラスをforms.pyのクラスで継承することができます。




Models.pyでテーブルとレコードを作成した後に、forms.pyを以下のように変更します。

from django import forms
from .models import Friend

class FriendForm(forms.ModelForm):
    class Meta:
        model = Friend
        fields = ['name','mail','age']


今回はFriendFormというModelFormを継承したクラスを作成し、その中でmodels.pyのテーブル(Friendクラス)とレコードを読み込んでいます。

このように書くことでmodels.pyとforms.py両方に同じようなコードを書く必要がなくなります。


またModelFormを活用することでviews.pyの記述もシンプルにすることができます。

views.py

if (request.method == 'POST'):
        obj = Friend()
        friend = FriendForm(request.POST,instance=obj)
        friend.save()
        return redirect(to = "/myapp")


先程は一つ一つを変数に格納する作業がありましたがいましたが、今回は簡単にインスタンスを作成することができました!



【Django】管理サイトからデータベースを操作する

f:id:mizuhiki0111:20190430175940p:plain


前回の記事の続きです

前回の記事



www.pythonmania.work




前回の記事ではSQLLiteを使用してデータベースに「Hello」というテーブルを作成しました。


フォームから送信した名前を登録できるように実装しましたが、これを管理サイトからも操作できるようにしてみます。



管理サイトはhttp://127.0.0.1:8000/adminにアクセスした際のページになります(デフォルトの設定)



①管理者の作成

管理サイトにログインするためには、まず管理者を登録する必要があります。


コマンドラインで

python manage.py createsuperuser

を実行し、「ユーザー名」・「メールアドレス」・「パスワード」の順に設定します。



②Helloテーブルを管理サイトから操作できるようにする


管理者を作成したので管理サイトにはログインできるようになりましたが、このままではHelloテーブルを操作することはできません。

管理ツールからHelloテーブルを操作できるように設定を変更する必要があります。


myapp/admin.pyを以下のように変更します。


from django.contrib import admin
from .models import Hello


admin.site.register(Hello)


このように記載することで管理サイトからHelloテーブルを操作できるようになります。




実際に管理サイトにアクセスしてテーブルを操作してみましょう



③管理サイトにアクセス


サーバーを立ち上げ、http://127.0.0.1:8000/adminにアクセスします。



ログイン画面が現れるので、①で登録したユーザー名とパスワードを入力してログインします。

ログインすると以下のような画面が現れると思います。



f:id:mizuhiki0111:20190515115303p:plain


ログインしたらMYAPPの「Hellos」と書いてあるボタンをクリックすると、Hellosテーブルが表示され、レコードの追加・削除が行えます。

※画像では「Friends」と書いてありますが気にしないでください笑



また「ユーザー」ボタンからは登録ユーザー・パスワードの変更などを行うことができます。


【Django】フォームから送信した情報をデータベースに登録してみる

f:id:mizuhiki0111:20190430175940p:plain


前回の記事でDjangoのmodels.pyの使い方について勉強しました。

前回の記事


www.pythonmania.work





今回はforms.pyとmodels.pyを活用して、フォームから送信されたデータをデータベースに登録する、ということをやってみたいと思います。


前提としてプロジェクトの作成やURLの設定等の事前準備は済ませているものとして進めていきます。

(事前準備は以下記事をご参照ください)

www.pythonmania.work



また今回はこちらの記事を参考にさせていただきました。

eiry.bitbucket.io





①モデルの定義

今回はフォームから送信された名前をデータベースに登録し、登録された名前をHTML上に順番に表示してみます。

from django.db import models


class Hello(models.Model):
    your_name = models.CharField(max_length=10)

    def __str__(self):
        return "<{0}>".format(self.your_name)

まずクラスを定義し、データベースにHelloという名前でテーブルを作成します。

次にカラムの作成ですが、今回はDjangoの「CharField」というフィールドを使用します。

これは文字列の型を扱うフィールドで、引数の指定により最大文字数を10文字に制限しています。


モデルの定義が終わったらmigrateしておきます。

python manage.py makemigrations

python manage.py migrate

②フォームの作成

次に名前情報を送信するようのフォームを作成します。

コードは以下のようになります。

from django import forms

class HelloForm(forms.Form):
    your_name = forms.CharField(
        max_length = 20,
        required=True,
        widget=forms.TextInput()
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['your_name'].widget.attrs['class'] = 'form-control'


③Views.pyの作成

Views.pyは以下のようになります。

from django.shortcuts import render,redirect
from .forms import HelloForm
from .import models

def hello_models(request):
    form  = HelloForm(request.POST or None)
    if form.is_valid():
        models.Hello.objects.create(**form.cleaned_data)
        return redirect('index')

    d = {
        'form' : form,
        'hello_qs': models.Hello.objects.all().order_by('-id'),
    }
    return render(request, 'myapp/index.html', d)

まず

form  = HelloForm(request.POST or None)

の部分でHelloFormクラスのインスタンスを作成します。



次に

 if form.is_valid():
        models.Hello.objects.create(**form.cleaned_data)
        return redirect('index')

の部分でformの内容(送信されたデータの形式)が正しければDBに情報を追加する処理を行っています。


戻り値の部分は通常であれば render関数を使用してテンプレートファイルをレンダリングするのですが、今回は「redirect」関数を使用しています。


これは「PRGパターン」という処理を実装するためのものです。

通常POST処理(フォームからの情報の送信等)を行った際に、ブラウザをリロードすると再度同じ投稿が行われてしまう、という現象が起こります。


これを回避するために、POSTリクエストが正常に処理された場合にはそのままHTMLのレスポンスを返すのではなく、別のURLパターンにリダイレクトする、という処理を行う必要があります。

そのためこの後解説するアプリのurls.pyでは複数のURLパターンを設定しています。

ちなみにredirectの引数である「index」はurls.pyで「name=」で設定した値になります。


最後に

 d = {
        'form' : form,
        'hello_qs': models.Hello.objects.all().order_by('-id'),
    }
    return render(request, 'myapp/index.html', d)

の部分でレンダリングの設定を行っています。

'hello_qs': models.Hello.objects.all().order_by('-id')

はHelloテーブルのすべてのレコードを取得し、id順に並び変えて"hello_qs"変数に格納しています。




④アプリのurls.pyの設定

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^/', views.hello_models, name='index'),
    url(r'^models/$', views.hello_models, name="hello_models"),
]


今回用意するテンプレートファイルはindex.html一種類ですが、前述の通りPRGパターンでの処理を行うためURLは2種類用意されています。




⑤テンプレートファイルの作成

{% block content %}
<div class="container">
  {{ message }}

  <h1>名前を登録する</h1>
  <h2>登録</h2>
  <form method="post" action="">
    <div class="form-group">
    {{ form.errors.your_name }}
    <label>{{ form.your_name.label }} {{ form.your_name }}</label><br>
    <input type="submit" class="btn btn-primary" value="送信">
    {% csrf_token %}
   </div>
  </form>
  <hr>
  <h2>一覧</h2>
  {% for h in hello_qs %}
    {{ h.your_name }}<br>
  {% endfor %}
</div>
{% endblock %}


これでhttp://127.0.0.1:8000/myapp/modelsにアクセスすると正常に起動すると思います。


フォームから送信されたデータはデータベースに保存され、id順にhtmlに表示されていきます。



【Python】Djangoのmodels.pyについてまとめてみた

f:id:mizuhiki0111:20190430175940p:plain



前回の記事で画像ファイルのアップロードフォームを作成した際にmodels.pyのImageFieldを使用しましたが、どのような仕組みでデータベースと連携しているのか分かりにくかったので簡単にまとめてみます。






DjangoはSQLを書かなくてもデータベースを操作できる

Webアプリケーションを開発するときには、データをデータベースに格納したり、格納したデータ使ってを様々なことを行ったりします。

例えば名前やメールアドレスなんかを登録してログインする際の認証に使ったりしますが、この場合は「名前」や「メールアドレス」といった情報がデータベースに保存され、これを取り出して使用したりしています。

このようなデータベースの情報の操作には通常「SQL」という言語が使われ、SQLでデータベースに対する命令を記載して使用します。
(例えば「SELECT * FROM TABLE_NAME~」みたいな感じ)


ですがDjangoで作成したアプリケーションでデータベースとのやり取りを行う場合には、この「SQL」を使用しなくてもPythonでデータベースとのやり取りを行うことができます。


このデータベースとのやり取りの基本となるのがmodel.pyになります。


実際にmodels.pyに記載した例を見ながら仕組みについて説明していきます。

from django.db import models

class Test(models.Model):
    class Meta:
        db_table = 'test' 

    hoge = models.TextField(max_length=100) 

    def __str__(self):
        return self.title


models.pyではmodelsクラスを継承してclassを定義することでデータベースのテーブルを作成することができます。


上記の場合は

class Test(models.Model):
    class Meta:
        db_table = 'test' 

の部分でmodelsクラスを継承したTestクラスを作成し、"test"という名前のテーブルを作成しています。

次に

 hoge = models.TextField(max_length=100) 

の部分ですがDjangoに標準で搭載されているfieldの関数を使用して「hoge」という文字列を扱うカラムを作成しています。


カラムは名前だけ作成すればいい、というものではなく、効率よくデータベースを運用するためにはデータ型やその他の制限を設定する必要があります。


Djangoにはデータ型に応じた様々なフィールドが用意されており、例として以下のようなものがあります。



「django.db.models.fields.BooleanField」:真偽値
「django.db.models.fields.CharField」:可変長文字
「django.db.models.fields.TextField」:文字列
「django.db.models.fields.IntegerField」:数値
「django.db.models.fields.FloatField」:浮動小数点
「django.db.models.fields.DateField」:日付
「django.db.models.fields.DateTimeField」:日付と時刻



例で挙げたコードでは文字列を扱うTexitFieldを使用してカラムを作成しており、引数に「max_length=100」とすることで最大文字数を100文字に制限しています。





このようにmodels.pyにデータベースの定義をした後、すぐにアプリケーションにデータベースが反映されるわけではありません。



まずデータベースが変更となったことを記載したマイグレーションファイルを作成します。


マイグレーションファイルを作成するにはコマンドラインで以下を実行します

python manage.py makemigrations アプリ名


マイグレーションファイルを作成した後は、実際にデータベースの変更を適用します

python manage.py migrate

これでデータベースの変更がアプリに適用されました。