diadia

興味があることをやってみる。自分のメモを残しておきます。

さくらVPSを使ってdjangoを公開する まとめ

さくらVPSにcentos7を入れる

http://torajirousan.hatenadiary.jp/entry/2019/03/31/011303

centos7の初期設定

サーバーへ安全にssh接続できるような設定を行う。
http://torajirousan.hatenadiary.jp/entry/2019/04/22/172101
条件は以下の通り。

  • root以外のユーザからの接続
  • 公開鍵秘密鍵を使った認証
  • ssh接続用のport番号の変更

centos7にnginxをインストール

 http://torajirousan.hatenadiary.jp/entry/2019/04/22/224755

 

postgresqlをインストール、設定

http://torajirousan.hatenadiary.jp/entry/2018/09/10/054545

centos7にpython,djangoをインストール

python,pipのインストール
http://torajirousan.hatenadiary.jp/entry/2019/01/13/234422

centos7にdjangoをインストール

http://torajirousan.hatenadiary.jp/entry/2019/04/22/230911

gunicornをインストールしてサービス公開

http://torajirousan.hatenadiary.jp/entry/2019/04/27/185130

サーバー構築 ssh関係

前提の説明

centos7を入れたばかりのサーバーには、ssh root@***.***.***.***で接続することができる。もちろんrootユーザーのパスワードが必要ではあるが、パスワードさえ分かれば接続できてしまう。
言い換えればデフォルトのsshの設定では不特定多数の第三者でも接続できる状態 を意味する。
この記事はsshでサーバーに接続する方法論ではない。不特定多数の第三者でも接続できる状況から如何にセキュリティを上げ、自分だけが接続できる状態にするか、これが本記事の主題なのである。この記事では様々な設定を行っていくのだが、それらはすべてセキュリティ向上の手段の1つとして認識すると一体的な理解につながる。

その他詳しいことが知りたければこちらを読めばある程度わかるようになると思われる。
http://www.unixuser.org/~euske/doc/openssh/book/chap4.html

想定環境

  • centos7

概要

ssh接続するには以下のコマンドをクライアント側(ローカル)で入力する。このコマンドを成立させるための準備を行えば、セキュリティを担保したssh接続ができる。

ssh -p [22以外のポート番号] -i [秘密鍵] rootでは無いユーザ名@サーバのipまたはドメイン

このコマンドを入力するためには

  • rootではないユーザでしか認証できないようにすること
  • 22以外のポート番号を準備すること
  • 公開鍵周りを準備すること(=パスワード認証の拒否を設定すること)

この3つが必要となる。これを設定することで、特定のユーザー名と特定のポート番号と特定の鍵情報をもっていないとサーバーに接続できなくなる。これは最初のsshの接続条件とは大きく変えることができる。

 

特定のユーザでしか認証できないようにすること

 まず特定のユーザーを作成すること。そしてrootによる接続を拒否する設定をする。これで"rootではないユーザでしか認証できないようにすること"が可能になる。

特定のユーザーを作成する

サーバーにて以下のコマンドを実行する。

# userを作成
useradd hoge
# 作成したuserのpasswordを設定 hogeはuser名
passwd hoge

 

rootによる接続を拒否する

rootによる接続を拒否するには、サーバー側のsshに関する設定ファイル(sshd_config)を変更すれば良い。

# 設定ファイルの編集
vi /etc/ssh/sshd_config
#PermitRootLogin yesをnoに変更する
PermitRootLogin no
PasswordAuthentication no

 

サーバにssh用のポートを準備すること

ざっくり言えば、

  1. ポートの番号設定
  2. firewallの当該ポート番号を許容する設定

をすることになる。

ポートの番号設定

ssh用のポート番号設定は、ssh関係の設定ファイルのポート番号を変更するだけで良い。イメージとしては、設定(config)ファイルをvi(m)で変更して上書きする。 設定ファイルは/etc/ssh/sshd_config である。

vi /etc/ssh/sshd_config

例えばポート番号を15156と適当に決めたとすると、#Port 22と書いてある場所を見つけ Port 15156と書く。ポート番号をデフォルトの22から変更するのは、他の人にサーバを乗っ取られにくくするためである。

#Port 22
上記を下記に書き換え
Port 15156

これでポート番号の設定は完了しました。sshd_configを変更したら更新するために以下を行う。

# centos7の場合はsshdをrestartするためにfirewallの設定を一時無効化するsetenforce 0を必要があります
# setenforce 0
# systemctl restart sshd.service

firewallの当該ポート番号を許容する設定

ポート番号を変更したらとfirewallも設定変更するはルールになります。したがって今からfirewallの設定を変更すること、変更したことを反映させる作業をします。
留意点は、firewallの設定(定義)ファイルが/usr/lib/firewalld/services/ssh.xmlというパスで存在しています。これを直接編集せず、このファイルをコピーし、/etc/firewalld/services以下に置く。コピーした定義ファイルをsshd_configで設定したポート番号を許容するために記述するということです。

一般的に/etcにはサービス(デーモン)の設定ファイルを配置するようです。したがって設定の雛形と言えるべき/usr/lib/firewalld/services/ssh.xmlをコピーし、/etc以下に配置します。
参考:https://oshiete.goo.ne.jp/qa/8029047.html

 

# ファイアウォールの定義ファイルをコピー
# cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services

 

# コピーした設定ファイルにポート番号22から変更ポート番号に記述変更
    # vi /etc/firewalld/services/ssh.xml
<port protocol="tcp" port="15156">

上記のコマンドで設定ファイルを変更することができた。
次に設定変更を反映させるコマンドを入力します。

# 設定変更をfirewallに反映させる
# firewall-cmd --reload

公開鍵周りの準備

サーバに接続する方法としてセキュリティを上げるため公開鍵認証を用いる。やり方は対となる公開鍵と秘密鍵を作る。公開鍵をサーバ(authorized_keysファイル)に登録する。ローカルには秘密鍵を保持しとく。そして上記のsshコマンドのように秘密鍵を使いssh接続する。これを実現するには、

  1. 公開鍵秘密鍵を作成する
  2. 公開鍵をサーバに送る
  3. 送られた公開鍵をauthorized_keysファイルに登録する。

なおsshがわけがわからなくなるのは、クライアント側で行う処理とサーバー側で行う処理を分けて整理できていないことが原因だった。クライアント、サーバーを明示する。

公開鍵秘密鍵の作成(クライアント側)

作成方法はmacwindowsで異なる。
windowsの場合は、teratermを使ってssh鍵を作成する。
macの場合はすでにopen-sshがインストールされているので以下のコマンド入力で鍵を作成できる。

$ ssh-keygen -t [鍵タイプ]

鍵タイプはrsaを選択する。だから以下のコマンドになる。

$ ssh-keygen -t rsa

また鍵は-fを追加するとファイル名を定めることができる。

$ ssh-keygen -t rsa -f [ファイル名]

特に-fオプションを使う理由が現状では見当たらない。

公開鍵をサーバに送る(クライアント側)

macの場合は以下のようにした。このときsshのポートを利用したけど、事前にポート開放とうしておかないといけないかも?

scp -P [ポート番号] -i [公開鍵] [送信したいファイルパス] [ユーザー名]@[サーバーのドメインorIP] : [ファイルのおきさき(ディレクトリ)]

具体例:

scp -P 22 -i id_rsa.pub /Users/takashi/.ssh/id_rsa.pub chiaki@156.345.134.431:/tmp 

サーバーのファイルの置く場所を指定すること。しないとファイルがいっこうに送信されない。ファイルが送れる場合、パスワードが要求された後、そのファイルが送信されたことが表示される。

クライアント側から受け取った公開鍵をauthorized_keysファイルに登録する(サーバー側)

sshの設定ファイル/etc/ssh/sshd_configに以下の内容がある。

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile      .ssh/authorized_keys

 

デフォルトで公開鍵のチェックは.ssh/authorized_keysを参照することになる。だから.ssh/authorized_keysを準備する必要がある。

mkdir .ssh
chmod 700 .ssh
cat id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

サイドバーを設置したい

https://getbootstrap.com/docs/4.3/examples/dashboard

構造を理解する

参考先の構造は、以下のようなものだった。

<div class="container-fluid">
<nav サイドバーの役割></>
<main メインの役割></>

</div>

ここで新たにわかったことはメインタグはセクショニングコンテントではないので、ドキュメントのアウトラインに影響を与えない。

sqlite:DBに格納されたテーブルデータを確認する方法

djangoでは開発時にsqlite3が使われる。このDBに直接接続し、データを入れてみようと思った。そのときにテーブル名が必要になる。どのような名前のテーブルか

参考文献:https://crimnut.hateblo.jp/entry/2018/04/17/172709

import sqlite3

con = sqlite3.connect("mydb.sqlite")
cursor = con.cursor()
cursor.execute("select * from sqlite_master where type='table'")
for x in cursor.fetchall():
    print(x)

con.close()

調べたいことはいろいろあるけど、とりあえずこのコードで 実行できた。

追記:SQLite3のテーブル確認だけしたいならDB Brouser(SQLite)を使えばコマンドを覚えておく必要はなくなるのでおすすめ。
補足情報:http://torajirousan.hatenadiary.jp/entry/2019/03/03/024103

ヘッダーとフッターのデザイン

ヘッダーとフッターのデザイン

わかったことがある。
スマホ等に画面を変更した場合、背景色があるヘッダーやフッターはフルで背景色が広がらない。

とても見栄えが悪い。ヘッダー、フッターは必ずフル画面に広がる設定でデザインすること。
bootstrap4では以下のクラスが役に立つ。

class="container-fluid"

sqlite3:エラー対処:sqlite3.OperationalError: near ")": syntax error

sqlite3.OperationalError: near ")": syntax error

このエラーがたまに出て、足止めをくらうのでメモにしておく。

コード

cur.execute("INSERT INTO mydb VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,)", (url,title,description,price,None,None,None,None,None,None,None,None,None,None))

 

エラーの意味が最初理解出来なかった。 これは閉じ括弧周辺に構文エラーがあることを示す。 今回は閉じ括弧の前に,をおいていることが原因だった。修正すると以下になる。

コード

cur.execute("INSERT INTO mydb VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (url,title,description,price,None,None,None,None,None,None,None,None,None,None))

sqlite3データベースの変更

sqlite3で既存のデータベースを修正したデータベースを作る必要が出てきた。

この作業は自分にとってヘビーだったので楽してできる方法を考る。今後同じケースにあたったときのために。

 

今回の方法

今回は別のファイルを作成した。拡張子がない”mydb”がファイル名だったが、これだとSQLAlchemyが読み込こまない問題が発覚した。

そこで"mydb.sqlite"と名付け、データをコピーすることになった。

工程

データベースファイルmydb.sqliteを作成

テーブルを作成

前データベースからデータ読み込み、リスト型データ化、新データベースに更新登録(カラムを分けて実施)

 

これが時間かかった。次回からはインサート一本で行う方法を用いる。

改善工程

データベースファイルmydb.sqliteを作成

前データベースからデータをcsv化する

テーブル作成

インサート

 

 

 

 

 

SQLAlchemy:エラー対処:sqlalchemy.exc.ArgumentError: Unknown arguments passed to Column: ['precision', 'asdecimal']

エラーコード 
sqlalchemy.exc.ArgumentError: Unknown arguments passed to Column: ['precision', 'asdecimal']

 

コード
class Product(Base):
    __tablename__ = 'mydb_jp'
 
    description     = Column(Text)
    price           = Column(Float, precision=(10,0), asdecimal=True)
    

どうやらFloatからエラーが発生している。sqlalchemyの場合Floatを使ってdecimalのデータ型に変更するようだ。 でdecimalのデータ型に変更する際に引数がいる。そういうわけで引数を書いたら知らない引数が渡されています、とエラーが出てしまった。解消しだい更新するとする。

SQLAlchemy:エラー対処:sqlalchemy.exc.OperationalError: (OperationalError) unable to open database file None None

エラーメッセージ:

sqlalchemy.exc.OperationalError: (OperationalError) unable to open database file None None

 

エラーが出た背景

sqlite3のデータベースを読み込みいろいろ変更しようとする際に起きた。

エラー部分

engine = create_engine('sqlite:///mydb')

原因解消

どうやらsqlite3のデータベースを開くことが出来ないことに起因するエラーだった。sqlite3のデータベースを拡張子なしで作ってしまったことが原因だった。新たにmydb.sqliteというファイル名でデータベースを作成し、以下のコードを書いた結果エラーは出なかった。

engine = create_engine('sqlite:///mydb.sqlite')

したがってsqliteでデータベースを作成する際は拡張子をちゃんと書くのが教訓となった。

参考:sqlite3のデータベースの作り方

import sqlite3
connection = sqlite3.connect(dbpath) 
# 例えばconnectの引数として"mydb"とした場合でmydbがなければ、新たにmydbというファイルが作成される。
''' 新たにdbファイルを作る場合、拡張子がなくても作ることができる。しかし他のモジュール利用のためにも.sqlite等の拡張子をつけるべき。'''

SQLAlchemy

参考文献:https://it-engineer-lab.com/archives/1183

sqlite3とdjangoのmodelsとSQLalchemyの共通点と差異についてメモできるとよい。

sqliteはそもそもすべてのデータをテキストのデータとして保存している。。。?

https://blog.ohgaki.net/sqlite-data-type-specification

 

データ型について

floatとdecimal

https://docs.sqlalchemy.org/en/latest/core/type_basics.html#sqlalchemy.types.Float

floatとdecimalはFloatを使って表現する。

Floatのasdecimal=Trueに設定した場合にDecimalとなる。

 

djangoの場合は

TextFieldがあるけどこれはどうなっているのか。

SQLAlchemyの場合でもTextがあるようだ。

 

djangoの場合はDecimalFieldで登録していたけど、

sqlite3は便宜的にIntegerにしてた。これは問題ないか?

sqlalchemyの場合は、Floatでasdecimal=Trueにすればdecimalが使える。

 

 

 

モデルの作成について

分かったこと。 データベースのテーブルデータを呼び出すためにモデルの作成がある。
例えばsqlite3のテーブルデータを呼び出すには、sqlite3のテーブルを自分で作成する必要がある。
その作り方はBaseモデルを継承して呼び出したいテーブルに似せたものを作る。この工程はdjangoのテーブルを作成する方法に似ている。

 

from sqlalchemy.ext.declarative import declarative_base

# まずベースモデルを生成します
Base = declarative_base()

# 次にベースモデルを継承してモデルクラスを定義します
class Product(Base):
    __tablename__ = 'mydb'
 
    title           = Column(String(255))
    description     = Column(Text)
    price           = Column(Integer)

 

わかったことは実際にテーブルに存在しないアトリビュートをモデルクラスとして定義すると、エラーが出てしまう。したがってテーブルのカラム名を正確に記述しなければいけない。

 

CRUDについて

SQL文の実行においてsqlite3でcur.execute()メソッドを使う。
SQLAlchemyの場合はsession.[sessionのメソッド名]()という形で行う。
例えば以下のようになる。

  • add() -- INSERT
  • query() -- SELECT
  • filter() -- WHERE

ドキュメント(チュートリアル

https://www.pythoncentral.io/migrate-sqlalchemy-databases-alembic/
sqlalchemyはAlembicを使って動かしているようだ。

psycopg2についてメモ

分からないことは、pysopg2とpsycopg2-binaryの違い。これはどうやって使い分けるのか。コンパイラや外部のライブラリ等を必要としないのがバイナリの方らしい。

そういう使い分け。

You can also obtain a stand-alone package, not requiring a compiler or external libraries, by installing the psycopg2-binary package from PyPI:

https://pypi.org/project/psycopg2/

コードを走らせる際に必要なライブラリがあるらしい。それがlibpqなるもののようだ。これをbinaryバージョンは別に準備しなくても実行できるってことのようだ。 

 

 

psycopg2ドキュメントから得たい情報

 http://initd.org/psycopg/docs/

 

自分が知る必要がある情報

一通りの流れのコマンド

csv読み込んでアップデートする方法

csv読み込んでインサートする方法

sqlite3,postresqlのsql文とどう違っているのか

 

一通りの流れのコマンド

http://initd.org/psycopg/docs/usage.html#basic-module-usage

>>> import psycopg2

# Connect to an existing database
>>> conn = psycopg2.connect("dbname=test user=postgres")

# Open a cursor to perform database operations
>>> cur = conn.cursor()

# Execute a command: this creates a new table
>>> cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);")

# Pass data to fill a query placeholders and let Psycopg perform
# the correct conversion (no more SQL injections!)
>>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)",
...      (100, "abc'def"))

# Query the database and obtain data as Python objects
>>> cur.execute("SELECT * FROM test;")
>>> cur.fetchone()
(1, 100, "abc'def")

# Make the changes to the database persistent
>>> conn.commit()

# Close communication with the database
>>> cur.close()
>>> conn.close()

postgresqlpythonのデータ型の対応

http://initd.org/psycopg/docs/usage.html#adaptation-of-python-values-to-sql-types

 

postgresqlに接続する

ドキュメントではconn = psycopg2.connect("dbname=test user=postgres")と書いてあるけど、パスワードを渡す場合は引数にパスワードを使えばよい。

http://initd.org/psycopg/docs/module.html
また別の方法として、
DATABASE_URL = postgresql://{username}:{password}@{hostname}:{port}/{database}
これを使う方法もある。

conn = psycopg2.connect(DATABASE_URL)

補足:hostnameはlocalhostとすればローカルのpostgresqlにつなげる。

データベースにデータをインサートする

sqlite3の使い方とほぼ同じ。curオブジェクトをつくり、execute()メソッドを実行する。両者の違いは?を使うか%sを使うかだけだ。

#参考:pythonのsqlite3の使い方
import sqlite3

conn = sqlite3.connect("mydb.sqlite3")
cur  = conn.cursor()
INSERT_SQL = """INSERT INTO test_teable (c1, c2, c3) VALUES (?,?,?)"""
t = ("テスト", "インサート文", "やり方",)
cur.execute(INSERT_SQL, t)
conn.commit()
#参考:pythonのpsycopg2の使い方
import psycopg2

conn = psycopg2.connect(DATABASE_URL)
cur  = conn.cursor()
INSERT_SQL = """INSERT INTO test_teable (c1, c2, c3) VALUES (%s,%s,%s)"""
t = ("テスト", "インサート文", "やり方",)
cur.execute(INSERT_SQL, t)
conn.commit()

参考:
https://www.lewuathe.com/python/postgresql/remind-for-insert-into-with-psycopg2.html
https://algorithm.joho.info/programming/python/sqlite3-insert-into/

django-allauthのログインリンクのはり方

webアプリケーションのnavバーにログインリンクをはろうと試みた。

メモしておく。

 

試みたこと

いつものようにapp_nameをアプリurls.pyで定め、app.urls.pyでnameを定める計画をする。しかしそもそもこれは自分が作ったアプリではない。てことで少し悩む事になった。

django-allauthのurls.pyに直接app_name="accounts"を書き込んでみた。

app_nameは読み込めるようになったが、nameは読み込めない。

 

nameはそもそもどこで確認するか。

それはもちろんallauth内のurls.pyであるが、自分の場合は以下のパスとなっていた。

/anaconda3/envs/django36/lib/python3.6/site-packages/allauth/account/urls.py

githubの方がコードの確認はしやすい。
https://github.com/pennersr/django-allauth/blob/master/allauth/account/urls.py

urlpatterns = [
    url(r"^signup/$", views.signup, name="account_signup"),
    url(r"^login/$", views.login, name="account_login"),
    url(r"^logout/$", views.logout, name="account_logout"),
    ....................
    

ログインのnameは"account_login"だと判明した。

結論

リンクが貼れた結果のみ書くと、app_nameやnamespaceを特段気にせず、むしろ無視してnameのみ書く

 <a href="{% url 'account_login' %}">ログイン</a>"

django-allauth : テンプレートのカスタマイズ

django-allauthを使ってみた結果ユーザのログインページが味気ない感じだった。

ここを修正していこうと思う。

 

https://qiita.com/s-katsumata/items/b667c81a127223d2e868

こちらにテンプレートのカスタマイズ方法があった。これを参考にテンプレートをカスタマイズしてみようと思う。

django-allauthのテンプレートのコピー

コマンドを使ってファイルを操作することに苦手なのでここもメモしておく。
まずコピーのコマンドは以下のような形式である。

 

#windowsの場合
copy コピー元ファイル コピー先のディレクトリ

#mac,linuxの場合
cp コピー元ファイル コピー先ディレクト

つぎにコピー元のファイルがどこに有るか?
django-allauthはpip でインストールした。pip でインストールした場合には、pip show モジュール名で情報参照できるようだ。

pipでインストールしたパッケージの場所を調べる

pip show django-allauth
Name: django-allauth
Version: 0.38.0
Summary: Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.
Home-page: http://github.com/pennersr/django-allauth
Author: Raymond Penners
Author-email: raymond.penners@intenct.nl
License: UNKNOWN
Location: /anaconda3/envs/django36/lib/python3.6/site-packages
Requires: python3-openid, requests-oauthlib, requests, Django
Required-by: 

locationがdjango-allauthのモジュールだ。ここからaccount,openid,socialaccount,base.htmlをディレクトリごとにコピーしておく。コピー先はテンプレートの優先順位を上げたい思惑からBASE_DIR/config/templates/allauth以下にコピーする。するとallauth以下にaccount,openid,socialaccountディレクトリが置かれる状態となる。
テンプレートはドキュメントで以下のように言及されている。

allauth ships many templates, viewable in the allauth/templates directory.

https://django-allauth.readthedocs.io/en/latest/templates.html#overridable-templates 

#参考
#mac, linuxの場合
cp -r /Users/chiaki/opt/anaconda3/lib/python3.7/site-packages/allauth/templates コピー先ディレクトリ
#-rオプションはディレクトリごとコピーすることができる

settings.pyのテンプレートの読み込み先を追加する

settings.pyのDIRSの欄にallauth部分を追加する。
djangoのテンプレートの読み込みは優先順序がある。それはtemplateのDIRSをまず読み込み、該当するテンプレートがなかった場合に各アプリのtemplatesディレクトリ(つまりAPP_DIRS)以下を読み込みに行く。そして言うまでもないが、各アプリはsettings.pyのINSTALLED_APPSに登録されて使われることが前提である。allauthの場合も同様、INSTALLED_APPSにallauthを登録するして初めてつかわれる。このことはテンプレートにおいてはallauthアプリ以下にあるテンプレートを読み込んでいるに過ぎない。したがってDIRSにカスタマイズしたallauthテンプレートのパスを記せば、カスタマイズのテンプレートを純正のテンプレートを無視して自己カスタマイズしたテンプレートを読みこむことになる。
https://docs.djangoproject.com/ja/2.2/topics/templates/#support-for-template-engines

具体的なコード例
config/settings.py にて
    
TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, "config", "templates"),
            os.path.join(BASE_DIR, "config", 'templates', 'allauth')],  # ←ココ
    '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',
            ],
        },
    },
]

#  上記の追加はBASE_DIR/config/templates/allauthのテンプレ読込先を追加したことを意味する!

上記の追加がなければ、BASE_DIR/config/templates以下のテンプレートをまず探して、該当テンプレートがなければAPP_DIRSを探す。そしてallauth純正のテンプレートを探し当てる。上記を追加すればBASE_DIR/config/templates以下のテンプレートをまず探す。なければ、BASE_DIR/config/templates/allauth以下にテンプレートがないか探す。ここにカスタマイズしたテンプレートを置けば純正allauthテンプレートを探す前に見つけてもらえるのでカスタマイズテンプレートが実際使われる。



テンプレートのカスタマイズ

各テンプレートはextends base.htmlとされているので、それに対しbootstrapのコードを加える。

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

forms.pyのカスタマイズ

forms.pyのフィールドにclassのアトリビュートを足してbootstrap効果をつけたいと考える。この場合はどうするか。。。?

https://django-allauth.readthedocs.io/en/latest/forms.html#forms

https://www.reddit.com/r/django/comments/3uykx8/customizing_djangoall_auth/

 

結論から言うと、settings.pyにカスタムしたフォームを使う宣言と、allauthのloginformを継承した子フォームさえ作成すれば良い。

 

settings.pyにカスタムしたフォームを使う宣言

ACCOUNT_FORMS = {'login': 'myapp.forms.CustomLoginForm'}
上記のように宣言すると、settings.pyにてallauth純正ではなく自分がカスタムしたフォームを使う挙動に変更される。したがってmyapp/forms.pyにてLoginFormを継承したクラスを作成すればよい。

https://django-allauth.readthedocs.io/en/latest/forms.html#account-forms

デフォルトでは以下のような設定になっているカスタムする場合は下記を参考にkeyをsettings.pyに書き込む。。

ACCOUNT_FORMS = {
    'login': 'allauth.account.forms.LoginForm',
    'signup': 'allauth.account.forms.SignupForm',
    'add_email': 'allauth.account.forms.AddEmailForm',
    'change_password': 'allauth.account.forms.ChangePasswordForm',
    'set_password': 'allauth.account.forms.SetPasswordForm',
    'reset_password': 'allauth.account.forms.ResetPasswordForm',
    'reset_password_from_key': 'allauth.account.forms.ResetPasswordKeyForm',
    'disconnect': `allauth.socialaccount.forms.DisconnectForm`,
}

allauthのloginformを継承した子フォームの作成

from allauth.account.forms import LoginForm


class CustomLoginForm(LoginForm):

	def __init__(self, *args, **kwargs):
		super().__init__(*args, **kwargs)
		for field in self.fields.values():
			field.widget.attrs['class'] = "form-control"