实例化Django模型会引发TypeError:isinstance()arg 2必须是类和类型的类,类型或元组

时间:2013-01-17 19:24:23

标签: django django-models

我有一个现有的功能性Django应用程序,在过去的几个月里一直在DEBUG模式下运行。当我将网站更改为在生产模式下运行时,当我点击试图创建新的推荐模型对象的特定视图时,我开始收到以下异常电子邮件。

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

如您所见,仅仅尝试实例化Referral模型对象会触发此异常。这是有问题的模型:

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中的错误还是我在不知不觉中做了一些我不应该做的事情?任何人都有修复或解决方法的建议吗?

5 个答案:

答案 0 :(得分:13)

更新(以下解决方案)

我一直在深入研究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上的已加载标志,以确定缓存是否已完全填充。如果不是,我们将强制缓存现在完全填充。问题将得到解决。

答案 1 :(得分:1)

另一个原因:

确保所有外键在同一应用程序(app标签)中的相同参考模型中。我在这一个人的头上撞了一会儿。

class Meta:
    db_table = 'reservation'
    app_label = 'admin'

答案 2 :(得分:1)

在我的情况下,我有一个模型“ Entity”和一个“ User”,它继承了“ AbstractBaseUser”。一个“用户”模型具有一个实体字段,该字段以这种方式配置了ForeignKey to Entity:

getRowNodeId={data => data.id}

最后,解决方法是将其更改为

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

我不知道问题的原因,但是它只是那样工作

答案 3 :(得分:0)

在我的情况下,我在类调用中犯了一个错误,将类名替换为引号,将其删除即可为我解决错误。看到下面的错误代码:

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,
    );

答案 4 :(得分:0)

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