0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

django.db.migrations.exceptions.CircularDependencyError エラーの回避方法

Posted at

原因

この循環依存エラー**"CircularDependencyError"**は、異なるアプリケーションのマイグレーションファイルがお互いのモデルを外部参照している場合に発生する模様。

エラー例

二つのアプリ"app1","app2"でお互いのモデルをForeignKeyでリレーションしているとき

app1/models.py
from django.db import models

class model_A(models.Model):
    id = models.AutoField( primary_key=True )
   
class model_B(models.Model):
    id = models.AutoField( primary_key=True )
    app2_a_model = models.ForeignKey('app2.model_A', on_delete=models.CASCADE)
app2/models.py
from django.db import models

class model_A(models.Model):
    id = models.AutoField( primary_key=True )
   
class model_B(models.Model):
    id = models.AutoField( primary_key=True )
    app1_a_model = models.ForeignKey('app1.model_A', on_delete=models.CASCADE)

makemigraionsを実行すると

python manage.py makemigrations app1
python manage.py makemigrations app2

お互いに依存しあったマイグレーションをファイルが出来上がり

app1/migrations/0001_initial.py
    ...
    dependencies = [
        ('app2', '0001_initial'),
    ]
    ...
app2/migrations/0001_initial.py
    ...
    dependencies = [
        ('app1', '0001_initial'),
    ]
    ...

CircularDependencyErrorが発生する。

django.db.migrations.exceptions.CircularDependencyError: app1.0001_initial, app1.0001_initial

解決策

アプリの役割を整理して循環依存状態を解消するのが良いかも知れないが、ここでは循環依存状態のままマイグレーションを成功させる方法を模索。

一つ分かっている事は、アプリ同士のモデルが依存し合っていても、依存先のマイグレーション世代が異なればCircularDependencyErrorは発生しない。

そこで一時的に循環依存状態を解消してマイグレーションファイルを作成してから循環依存状態に戻し次の世代のマイグレーションファイルを作成する事に。

手順としては、

  • app1のmodel_Bモデルのリレーション先を'app2.model_A'からダミーモデル'Dummy_model'に変更してapp1 をmakemigraions
  • app2をmakemigraions
  • app1のmodel_Bモデルのリレーション先を元に戻してapp1をmakemigraions
# 循環依存解消 
cp -pi app1/models.py app1/models.py.ori
sed "s/'app2.model_A'/'Dummy_model'/" app1/models.py.ori > app1/models.py
# ダミーモデルを追記
cat >>app1/models.py <<'__EOF__'
class Dummy_model(models.Model):
    id = models.AutoField ( primary_key=True )
__EOF__
python manage.py makemigrations app1
python manage.py makemigrations app2
# app1のmodel_Bモデルのリレーション先を元に戻す。
mv -f app1/models.py.ori app1/models.py
python manage.py makemigrations app1
# マイグレーションを実行
python manage.py migrate

これでmigrateを実行するとエラーが解消される。

makemigration実行時に、特定フィールドやテーブルだけ除外する方法は、無かった。
もっとスマートな方法はないだろうか?

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?