Python/Django 遭遇したエラー集と解決方法

Python/Djangoでコーディングをしていると、まだまだ見慣れないエラーに遭遇することが多く
また、ググっても解決策が見つかることも少なくエラー原因の調査も一苦労という状態です。

そこで同じようにエラー原因を調べて途方に暮れている方々(ほとんど自分向け)に
発生したエラーと解決した手順を書き連ねていこうと思います。

同じエラーが出たからと言って、同じ原因であることはもちろん少ないですが
今後のコーディング時の調査時間が多少なりとも少なくなるといいでいすね。
Python:3.9.4
Django:3.2

Can't create table django_admin_log

アプリを作成して早速動かそう!と思ったときに表示されたエラー
焦って大事な手順を飛ばしています。
「django_admin_log」テーブルがないというエラーですが、そもそもテーブルが存在しておりませんでした。
migrateしていないので、テーブルがありません
エラーメッセージの中のテーブル名は、一番最初にエラーになったものが表示されております。
今回はログを出力しに行った際に、エラーになったということですね。
原因は分かったので、migarateのコマンドを流すだけです。
一応下記に記載いたします。

manage.py makemigrations

「manage.py」のあるディレクトリに遷移し、マイグレーションファイルを作成します。

manage.py migrate

マイグレーションを実行します。これでテーブルが作成されますので、再度アプリを動かしてみましょう。

'auth.User' has been swapped for

Djangoが提供しているUserモデルをカスタマイズした際に遭遇したエラーです。
エラーの内容は『カスタムユーザが作成されてimportしてるけど、デフォルトのUserモデルを使ってるところもあるよ』と
指摘されています。
「has been swapped for」を直訳すると

「交換されている」

もしくは

置き換わられている

という意味になります。原因がわかると、エラーの意味の分かってきますね。
例えば
from user.models import User

def loginfunc(request):
    if request.method == "POST":
        email = request.POST['email']
        password = request.POST['password']
        auth_object = EmailAuthBackend()
        user = auth_object.authenticate(email=email, password=password)
このように、作成したカスタムユーザを使っている中で、別のプログラムでデフォルトのUserモデルを使った場合に エラーが発生します。
from django.contrib.auth.models import User

class EmailAuthBackend(ModelBackend):
    def authenticate(self, email=None, password=None, **kwargs):
        if email is None or password is None:
            return
        try:
            user = User.objects.get(email=email)
        except UserModel.DoesNotExist:
            return None
/login/ページにアクセスすると、このようなエラーメッセージが表示されます。
swapped forエラー画面

解消方法

カスタマイズしたUserモデルとデフォルトのUserモデルが共存できないようなので、デフォルトのUserモデルを使っている箇所を全てカスタマイズしたUserモデルに置き換えていきましょう。
#from django.contrib.auth.models import User
from user.models import User


class EmailAuthBackend(ModelBackend):
    def authenticate(self, email=None, password=None, **kwargs):
        if email is None or password is None:
            return
        try:
            user = User.objects.get(email=email)
        except UserModel.DoesNotExist:
            return None

'NoneType' object has no attribute 'attname'

このエラーやよくわからなかったのですが、エラーが発生していたクラスに
initの処理を追加してエラー解消しました。

def __init__(self, *args, *kwargs): 
  super().__init__(args, **kwargs)
本当は正しく理解してから進めないといけないのですが
こちらは一旦放置

MySQLdb._exceptions.OperationalError: (1051, "Unknown table 'アプリ名.user_user_groups'")

migrationしたときにエラー発生。これからテーブルを作ろうとしているのに見つからないとはどういうことだと思いましたが
そもそもテーブルを作成することができていなかったようです。
models.pyなどを触ってはmigrateして修正してを繰り返していくうちに
テーブル間の外部結合などの影響で、テーブルを消したり更新したりできなくなっていることがあります。
その際に、中途半端にしかテーブルが作成されていないと

テーブルがないよ

とエラーを吐き出してくれます。
エラーメッセージの最初の部分は、利用しているDBによって異なります。
今回はMySQL利用していたので「MySQLdb._exceptions」と表示されております。

解消方法

下記の手順で解消しました。ただし、テーブルを丸ごと消すので、テストデータなどもすべて削除することになる点は要注意
何も考えず本番環境で実行することは止めてください!データ消す手順です!!
  1. migrationsフォルダに入っているファイルを「__init__.py」を残してすべて削除
  2. 作成されたテーブルを全てドロップ
  3. 再度migrateを実行
これで無事にすべてのテーブルが作成されていれば、エラーは解消しています。

You have multiple authentication backends configured and therefore must provide the backend argument or set the backend attribute on the use

こちらは認証バックエンドを拡張していた際に遭遇したエラーメッセージです。
エラーメッセージを要約すると

認証バックエンドが複数登録されてるけど、どれ使うかわからないからバックエンド使うときに必ず指定して

という感じです(ざっくり)
認証バックエンドの拡張方法は別記事で紹介しようと思いますが
追加した認証バックエンドは下記の通り設定ファイルに追記することで利用できます。
AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'user.auth.EmailAuthBackend',  # 追加
]
設定ファイルに追加したあとは、『複数の認証バックエンドが定義されている状態』になるので
ログイン処理などで、利用する認証バックエンドの指定が必要になります。

解消方法

ログイン時の処理を下記のように修正します。
login(request, user)
login(request, user,backend='user.auth.EmailAuthBackend')
ログイン処理呼び出し時のパラメータが追加されていますね。
このようにして利用する認証バックエンドを指定します。

コメントを残す