11

我有一个现有的功能性 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

就我而言,我有一个模型“实体”和一个继承“AbstractBaseUser”的“用户”。“用户”模型有一个实体字段,其外键到实体的配置方式如下:

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

正如其他答案中已经强调的那样,最常见的原因似乎是指使用'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

现在打印出有问题的模型的名称,在代码中找到相关位置不再是一个大问题。

在 Django 2.2 上测试。

于 2021-04-09T21:22:03.620 回答
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 回答