Django:なぜいくつかのモデルフィールドが互いに衝突するのですか?


174

ユーザーへの2つのリンクを含むオブジェクトを作成します。例えば:

class GameClaim(models.Model):
    target = models.ForeignKey(User)
    claimer = models.ForeignKey(User)
    isAccepted = models.BooleanField()

サーバーを実行すると、次のエラーが発生します。

  • フィールド 'target'のアクセサーは、関連フィールド 'User.gameclaim_set'と競合します。「ターゲット」の定義にrelated_name引数を追加します。

  • フィールド 'claimer'のアクセサーは、関連フィールド 'User.gameclaim_set'と競合します。「クレーマー」の定義にrelated_name引数を追加します。

エラーが発生する理由と修正方法を教えてください。


これらのエラーメッセージは本当に良いです。彼らはすでにそれらを修正する方法を説明しています。そして、** [ related_nameドキュメンテーション] **(docs.djangoproject.com/en/dev/ref/models/fields/#arguments)を読んで、それらが発生する理由を説明します。
Lutz Prechelt 2017

回答:


294

Userに対する2つの外部キーがあります。Djangoは、UserからGameClaimへの逆の関係を自動的に作成しますgameclaim_set。通常はです。ただし、2つのFKがあるため、2つのgameclaim_set属性があり、これは明らかに不可能です。したがって、逆の関係に使用する名前をDjangoに伝える必要があります。

related_nameFK定義で属性を使用します。例えば

class GameClaim(models.Model):
    target = models.ForeignKey(User, related_name='gameclaim_targets')
    claimer = models.ForeignKey(User, related_name='gameclaim_users')
    isAccepted = models.BooleanField()

49
良い答えですが、無礼を回避するのに成功したとは思いません。
ケニー

14
フレームワークを学んでいるだけの人にとっては、これは明白ではありません。
jkyle

3
おかげで、エラーメッセージもはっきりしませんでしたが、逆の関係についての説明は非常に役に立ちました。
ルキー

1
クラッシュが良いバンドだったからといって、それらを特に説明的なエラーメッセージにしないでください;)
btown

7
また、すべてのモデルでリバース関係を使用する必要がない場合も言及する必要があります。場合によっては、モデルの関係を一方向にすることもできます。この場合、related_name = '+'を使用します。これはDjangoに一方向の関係を作成し、逆の関係を無視するように指示します。
トミーストランド2013年

8

Userこのモデルは、同じ名前のための1と2つのフィールドを作成しようとしているGameClaimsことを持っていることUserなどtargetのため、別GameClaimsのことを持っているUserようclaimer。ここだドキュメントには、related_name自動生成されたものが競合しないように、あなたは属性の名前を設定させるのDjangoの方法です。


7

OPは抽象基本クラスを使用していません...しかし、使用している場合は、FKでrelated_nameをハードコーディングすることで(たとえば、...、related_name = "myname")、これらの競合エラーが多数発生します。 -基本クラスから継承されたクラスごとに1つ。下記のリンクには回避策が含まれています。これは簡単ですが、明確ではありません。

django docsから...

ForeignKeyまたはManyToManyFieldでrelated_name属性を使用している場合は、フィールドに一意の逆引き名を常に指定する必要があります。このクラスのフィールドは各子クラスに含まれ、毎回属性(related_nameを含む)の値がまったく同じであるため、これは通常、抽象基本クラスで問題を引き起こします。

詳細はこちら


2

場合によってrelated_name は、継承を使用するときはいつでも、追加の書式設定を使用する必要があります。

class Value(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=5)
    animal = models.ForeignKey(
        Animal, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class Height(Value):
    pass

class Weigth(Value):
    pass

class Length(Value):
    pass

ここでは衝突はありませんが、related_nameが一度定義されると、Djangoが一意の関係名の作成を処理します。

次に、Valueクラスの子では、以下にアクセスできます。

herdboard_height_related
herdboard_lenght_related
herdboard_weight_related

0

たとえば、次のような構造の場合、サブモジュールをアプリケーションとしてdjangoプロジェクトに追加すると、この問題が発生することがあります。

myapp/
myapp/module/
myapp/module/models.py

以下をINSTALLED_APPSに追加すると、

'myapp',
'myapp.module',

Djangoはmyapp.mymodule models.pyファイルを2回処理するようで、上記のエラーをスローします。これは、INSTALLED_APPSリストにメインモジュールを含めないことで解決できます。

'myapp.module',

myapp代わりにを含めると、myapp.moduleすべてのデータベーステーブルが誤った名前で作成されるため、これは正しい方法のようです。

この問題の解決策を探しているときに私はこの投稿に出くわしたので、ここにこれを置くと思いました:)


0

ジョーダンの答えに追加するだけです(ジョーダンのヒントに感謝します)、アプリより上のレベルをインポートしてからアプリをインポートした場合にも発生する可能性があります。

myproject/ apps/ foo_app/ bar_app/

したがって、アプリ、foo_app、bar_appをインポートする場合、この問題が発生する可能性があります。アプリ、foo_app、bar_appがすべてsettings.INSTALLED_APPSにリストされていました

とにかくアプリをインポートしないようにします。同じアプリが2つの異なる名前空間にインストールされているためです。

apps.foo_app そして foo_app

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.