Djangoのマイグレーションで「django.db.utils.ProgrammingError: relation does not exist」が出たときの対処法

エラー解決
スポンサーリンク

Djangoのマイグレーションを実行したところ、以下のように「django.db.utils.ProgrammingError: relation <DBモデル> does not exist」が出ました。
いろいろ調べた結果解決できましたので、備忘録として残します。

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "hhbook_user" does not exist
LINE 1: ..."auth_user_id_id", "hhbook_user"."is_enable" FROM "hhbook_us...
                                                             ^
The above exception was the direct cause of the following exception:

Traceback (most recent call last):
・
・(Tracebackは省略)
・
django.db.utils.ProgrammingError: relation "hhbook_user" does not exist
LINE 1: ..."auth_user_id_id", "hhbook_user"."is_enable" FROM "hhbook_us...

 

解決策をすぐに見たい方は、「解決方法 まとめ」まで読み飛ばしてください。

 

目次

 


 

解決方法 まとめ

この解決方法が有効だと思われる事象

以下の事象に当てはまれば、この記事で紹介する解決策は有効ではないでしょうか

  • migrateコマンドどころか、makemigrationsshowmigrationコマンドでも同様なエラーが発生する。
  • テーブルが生成済みの既存DBでは、問題なくmigrateコマンドが実行できる。

  

解決方法

エラーが発生している箇所でクラス変数としてDBモデルを呼んでいないでしょうか?
もし呼んでいるようであれば、DBモデルをクラス変数ではなくコンストラクタ内で呼び出すようにすると解決できるかもしれません。

 

【DBモデルをクラス変数を呼んでいる例:】

DBモデルをクラス変数として呼んでいるところは、 for hhb_user in HhbookUser.objects.filter(is_enable=True): の箇所です。

from django import forms
from home.models import HhbookUser
class PaymentForm(forms.ModelForm):
    USER_LIST = []
    for hhb_user in HhbookUser.objects.filter(is_enable=True):
        USER_LIST.append((hhb_user.auth_user_id.id , hhb_user.get_username(20)))
    USER_LIST=tuple(USER_LIST)
    payment_user = forms.fields.ChoiceField(
        label='購入者',
        required = True,
        choices= USER_LIST,
        widget=forms.widgets.Select
    )

 

【修正例:】

コンストラクタ__init__(self, *args, **kwargs):内にDBモデルをいれました。

django import forms
from home.models import HhbookUser
class PaymentForm(forms.ModelForm):
    USER_LIST = []
    def __init__(self, *args, **kwargs):
        super(PaymentForm, self).__init__(*args, **kwargs)
        for hhb_user in HhbookUser.objects.filter(is_enable=True):
            self.USER_LIST.append((hhb_user.auth_user_id.id , hhb_user.get_username(20)))
        self.USER_LIST=tuple(self.USER_LIST)
        self.fields['payment_user'] = forms.ChoiceField(
            label='購入者',
            required = True,
            choices= self.USER_LIST,
            widget=forms.widgets.Select
        )

 

 

エラー解決までの流れ (個人用備忘録)

以下は自分が忘れないようにするために記載したもので、完全に個人用備忘録です。
まとまりがないですが、悪しからず。

 

テスト環境で「coverage test」を実行したらエラーが発生

開発環境では動いていた系をテスト環境で構築して、「coverage test」を実行したところ、、、下記エラーが発生。

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "hhbook_user" does not exist
LINE 1: ..."auth_user_id_id", "hhbook_user"."is_enable" FROM "hhbook_us...
                                                             ^
The above exception was the direct cause of the following exception:

Traceback (most recent call last):
・
・(Tracebackは省略)
・
django.db.utils.ProgrammingError: relation "hhbook_user" does not exist
LINE 1: ..."auth_user_id_id", "hhbook_user"."is_enable" FROM "hhbook_us...

 

relation "hhbook_user" does not exist」と言っており、DBモデル?テーブル?がないと言っている。
実際にテスト環境では"hhbook_user"というテーブルは生成されていなかった。

テーブルがうまく生成されていないということは、Djangoのマイグレーションに問題があるのではないかと考え、テスト環境で「manage.py migrate」を実行してみると、上記エラーと同じものがでた。
「coverage test」が問題ではなく、マイグレーションに問題があると分かった。

 

マイグレーション系のコマンドをいろいろ試してみる

「manage.py migrate」の実行エラーなら、再度マイグレーションファイルを作成すればいいのかと考え、「manage.py makemigrations」を実行してみたが、同じエラーが出た。

いろいろ調べた結果、以下のコマンドでそもそもエラーが出ていることが分かった。

  • manage.py migrate
  • manage.py makemigrations
  • manage.py showmigration

 

でも、開発環境ではマイグレーションは問題なく動いているし、、、
テーブルがないのが原因みたいだが、テーブルを作るマイグレーションで失敗するとは、、、どうすればいいのだ?

とりあえず、エラー内容をググってみることにした。

 

エラー内容をググってみた

「django.db.utils.ProgrammingError: relation <DBモデル> does not exist」でググってみた。

 

 

エラー内容でググると、いろいろ出てきたが、、、すべて解決できず。
migrateコマンドで発生するエラーについては多くあったが、makemigrationsshowmigrationコマンドで発生している事例は見かけなかった。

 

 

暫定解決? pathを無効にすればいける!

いろいろいじっていたら、urls.pyのurlpatterns[]にすればマイグレーションがうまくいくことが分かった。makemigrationsshowmigrationコマンドの実行もうまくいった。
マイグレーションが実行でき、テーブルが作成できるので、その後urlpatternsを元に戻してやれば問題なく動くことが確認できた!

【urls.py】

urlpatterns = [
    #path('', include('home.urls')),
    #path('hhbook/', include('hhbook.urls')),
    #path('admin/', admin.site.urls),
]
  • homeやhhbookは自分で作ったアプリ
  • admin.site.urlsはDjangoのログイン機能

 

とりあえず暫定解決はできそうだ!!!
だけど、テスト環境を構築するたびにurls.pyのurlpatterns[]にするのはめんどい。
本質的な解決にはなっていないので、もうちょい調べることにする。

上のコードでは、すべてのアプリをコメントアウトしているが、Djangoのログイン機能のみ有効にしてマイグレーションしてみたら、成功した。
つまり、自分のアプリがバグっている!ということだ笑

 

 

もう一度、エラー内容をよく見てみる

エラー内容の詳細(Traceback)

  File "/code/hhbook/urls.py", line 3, in <module>
    from . import views
  File "/code/hhbook/views.py", line 5, in <module>
    from .forms import PaymentForm,SearchForm
  File "/code/hhbook/forms.py", line 7, in <module>
    class PaymentForm(forms.ModelForm):
  File "/code/hhbook/forms.py", line 17, in PaymentForm
    for hhb_user in HhbookUser.objects.filter(is_enable=True):

 

PaymentFormのとこで、DBモデル"hhb_user"を読んでいて、それが異常の原因となっているようだ。
PaymentFormを見てみる。

from django import forms
from home.models import HhbookUser
class PaymentForm(forms.ModelForm):
    USER_LIST = []
    for hhb_user in HhbookUser.objects.filter(is_enable=True):
        USER_LIST.append((hhb_user.auth_user_id.id , hhb_user.get_username(20)))
    USER_LIST=tuple(USER_LIST)
    payment_user = forms.fields.ChoiceField(
        label='購入者',
        required = True,
        choices= USER_LIST,
        widget=forms.widgets.Select
    )

 

なんと、HhbookUser.objects.filter()PaymentFormクラスのクラス変数として、DBモデル(インスタンス変数)を呼んでいる!
これが原因ではないだろうか。。。。バグやんn

 

  

DBモデルをクラス変数ではなく、コンストラクタで呼ぶようにする

クラス変数としてインスタンス変数を呼んでいるのが原因なら、インスタンス変数をコンストラクタに入れればいい!
ということで、先ほどのPaymentFormを以下のように修正した。

django import forms
from home.models import HhbookUser
class PaymentForm(forms.ModelForm):
    USER_LIST = []
    def __init__(self, *args, **kwargs):
        super(PaymentForm, self).__init__(*args, **kwargs)
        for hhb_user in HhbookUser.objects.filter(is_enable=True):
            self.USER_LIST.append((hhb_user.auth_user_id.id , hhb_user.get_username(20)))
        self.USER_LIST=tuple(self.USER_LIST)
        self.fields['payment_user'] = forms.ChoiceField(
            label='購入者',
            required = True,
            choices= self.USER_LIST,
            widget=forms.widgets.Select
        )
  • ModelForm、ChoiceFieldでコンストラクタを作成する方法はググった。[7],[8],[9]

 

これでマイグレーションを実行してみたらうまくいった!
makemigrationsshowmigrationコマンドの実行もうまくいった。

 

 

自分のアプリのバグが原因でした

「django.db.utils.ProgrammingError: relation <DBモデル> does not exist」エラーの原因はアプリのクラス変数でDBモデルのインスタンス変数を呼んでいることでした。
Tracebackログを見ると、マイグレーション実行時にpathからアプリが使用するDBモデルを確認しているようです。
開発環境ではすでにマイグレーション済みのDBがあり、DBモデルがインスタンス化できるためこのエラーが発生しなかったようです。一方、テスト環境ではDBは空の状態のためDBモデルがインスタンス化できずこのエラーが出たのだと思います。

 

 

戒め

エラー内容をググるだけでなく、きちんとエラー発生個所に問題ないか確認しよう!!!

 

 

参考

[1] 【Django】 relation does not exist が発生してしまう。 | teratail
[2] django.db.utils.ProgrammingError: relation "auth_user" does not exist の解決 | teratail
[3] Djangoの初回マイグレーション時に relation "auth_user" does not exist というエラーが発生する場合 | Yura YuLife
[4] django.db.utils.ProgrammingError: relation “bot_trade” does not exist | stack overflow
[5] Django Rest Framework "django.db.utils.ProgrammingError:relation" patient "does not exist" | stackoverrun
[6] Users and Roles for DJango App running with Postgres dB in DO droplet | Community
[7] Django Model instance value in ModelForm constructor | stackoverflow
[8] django forms - overriding constructor for changing field type depending by input | stackoverflow
[9] DjangoのFormに初期値を設定する方法 | Freelance Note

 

 

広告

Djangoをやるなら以下の書籍がオススメです。
DjangoでWebアプリを開発するときの要点が分かりやすくまとめられています。

 


 

ConoHa VPS は初期費用不要で月に数百円で利用できる仮想サーバのサービスです。
以下のような方には非常にオススメのサービスとなっています!

  • 勉強がてらLinuxの環境をちょっと触ってみたい
    管理者権限が実行可能なLinuxサーバ環境が構築可能です!
  • スモールスタートでサービスを提供して、うまくいったら規模をスケールアップしたい
    後からメモリサイズやCPU数などのスケールアップ/スケールダウン可能です!
  • AWSやGCPなどのクラウドサービスは高いので、もっと安くサーバ構築したい
    初期費用なし、月数百円(1時間単位も可)で利用可能です!

 

以上!

コメント

タイトルとURLをコピーしました