さくらVPSを使ってdjangoを公開する まとめ
さくらVPSにcentos7を入れる
http://torajirousan.hatenadiary.jp/entry/2019/03/31/011303
centos7の初期設定
サーバーへ安全にssh接続できるような設定を行う。
http://torajirousan.hatenadiary.jp/entry/2019/04/22/172101
条件は以下の通り。
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をインストールしてサービス公開
サーバー構築 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用のポートを準備すること
ざっくり言えば、
- ポートの番号設定
- 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接続する。これを実現するには、
- 公開鍵秘密鍵を作成する
- 公開鍵をサーバに送る
- 送られた公開鍵をauthorized_keysファイルに登録する。
なおsshがわけがわからなくなるのは、クライアント側で行う処理とサーバー側で行う処理を分けて整理できていないことが原因だった。クライアント、サーバーを明示する。
公開鍵秘密鍵の作成(クライアント側)
作成方法はmacとwindowsで異なる。
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()
postgresqlとpythonのデータ型の対応
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 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"