11

過去数か月間DEBUGモードで実行されている既存の機能的なDjangoアプリケーションがあります。サイトを本番モードで実行するように変更すると、新しい参照モデルオブジェクトを作成しようとする特定のビューにアクセスすると、次の例外メールが送信され始めます。

Traceback (most recent call last):

 File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/core/handlers/base.py", line 111, in get_response
   response = callback(request, *callback_args, **callback_kwargs)

 File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/contrib/auth/decorators.py", line 20, in _wrapped_view
   return view_func(request, *args, **kwargs)

 File "/var/django/acclaimd2/program/api.py", line 807, in put_interview_request
   referral = Referral()

 File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/db/models/base.py", line 349, in __init__
   val = field.get_default()

 File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/db/models/fields/related.py", line 955, in get_default
   if isinstance(field_default, self.rel.to):

TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types

ご覧のとおり、参照モデルオブジェクトをインスタンス化しようとすると、この例外がトリガーされます。問題のモデルは次のとおりです。

class Referral (models.Model):
    opening = models.ForeignKey(Opening,related_name='referrals',null=False,blank=False)
    origin_request = models.ForeignKey('common.request',related_name='referrals',null=True,default=None)
    candidate = models.ForeignKey(User,related_name='referrals',null=False,blank=False)
    intro = models.TextField(max_length=1000,null=False,blank=False)
    experience = models.TextField(max_length=5000,null=False,blank=False)
    email = models.CharField(max_length=255,null=False,blank=False)
    phone = models.CharField(max_length=255,null=False,blank=True,default='')

    def __unicode__(self):
        return u"%s" % self.id

これはDjangoのバグですか、それとも私が知らないうちにすべきでないことをしているのでしょうか?誰かが修正や回避策について何か提案がありますか?

4

5 に答える 5

18

更新(以下の解決策を含む)

Djangoモデルコードを掘り下げてきましたが、ForeignKeyの関連フィールドに「app.model」ベースの識別子を使用すると競合状態が発生するバグがあるようです。アプリケーションがDEBUGではなく本番モードで実行されている場合、上記の例外で参照されているForeignKey.get_defaultメソッドは、指定されたデフォルト値が関連フィールド(self.rel.to)のインスタンスであるかどうかを確認しようとします。

def get_default(self):
    "Here we check if the default value is an object and return the to_field if so."
    field_default = super(ForeignKey, self).get_default()
    if isinstance(field_default, self.rel.to):
        return getattr(field_default, self.rel.get_related_field().attname)
    return field_default

最初に、ForeignKeyが文字列ベースの関連フィールドでインスタンス化されると、self.rel.toが文字列ベースの識別子に設定されます。related.pyには、add_lazy_relationという別の関数があり、通常の状況では、この文字列ベースの識別子をモデルクラス参照に変換しようとします。モデルは遅延してロードされるため、AppCacheが完全にロードされるまでこの変換を延期できる可能性があります。

したがって、AppCacheが完全に設定される前に文字列ベースのForeignKeyリレーションでget_defaultが呼び出されると、TypeError例外が発生する可能性があります。どうやら、アプリケーションを本番モードにすると、モデルのキャッシュのタイミングがずれて、このエラーが発生し始めたようです。

解決

これは本当にDjangoのバグのようですが、この問題が発生した場合の回避方法は次のとおりです。厄介なモデルをインスタンス化する直前に、次のコードスニペットを追加します。

from django.db.models.loading import cache as model_cache
if not model_cache.loaded:
    model_cache._populate()

これにより、AppCacheにロードされたフラグがチェックされ、キャッシュが完全に設定されているかどうかが判断されます。そうでない場合は、キャッシュを強制的に完全に追加します。そして、問題は解決されます。

于 2013-01-18T00:06:03.670 に答える
5

私の場合、モデル「Entity」と「AbstractBaseUser」を継承した「User」がありました。'User'モデルには、ForeignKeytoEntityがそのように構成されたエンティティフィールドがありました。

entity = m.ForeignKey('core.Entity', on_delete=m.SET_NULL, null=True)

結局のところ、回避策はそれをに変更することでした

from core.models import Entity
entity = m.ForeignKey(Entity, on_delete=m.SET_NULL, null=True)

問題の原因はわかりませんが、そのように機能します

于 2020-01-23T08:28:05.477 に答える
1

別の原因:

すべての外部キーが同じアプリケーション(アプリラベル)の同じ参照モデルにあることを確認してください。しばらくの間、壁に頭をぶつけていました。

class Meta:
    db_table = 'reservation'
    app_label = 'admin'
于 2013-02-04T20:19:14.697 に答える
1

私の場合、クラス名を引用符で囲んでクラス呼び出しを間違えました。それらを削除すると、エラーが解決しました。以下の間違ったコードを参照してください。

from django.db import models
from django.contrib.auth.models import AbstractUser
from account.models import Profile

class User(AbstractUser):
    first_name = None;
    last_name = None;
    profile = models.ForeignKey(
        'Profile',
        on_delete=models.CASCADE,
    );
于 2020-02-10T11:36:03.067 に答える
1

他の回答ですでに強調されているように、最も一般的な原因は、'app.Model'構文を使用してモデルを参照しているようです。

ただし、どのモデルが問題を引き起こしているのかを正確に把握することは、依然として非常に大きな課題となる可能性があります。

その質問に対する簡単な解決策は、例外が発生した場所(django.db.models.fields.related.ForeignKey.get_default)に直接移動し、次の印刷ステートメントを追加することです。

    def get_default(self):
        """Return the to_field if the default value is an object."""
        field_default = super().get_default()
        # Add this line:
        print(f'Here is our small little bug: {field_default}, {self.remote_field.model}')
        if isinstance(field_default, self.remote_field.model):
            return getattr(field_default, self.target_field.attname)
        return field_default

これで、問題のあるモデルの名前が出力され、コード内の関連する場所を見つけることはもはや大きな問題ではなくなりました。

Django2.2でテスト済み。

于 2021-04-09T21:22:03.620 に答える