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

时间:2021-09-22 16:57:19

I have an existing, functional Django application that has been running in DEBUG mode for the last several months. When I change the site to run in production mode, I begin getting the following Exception emails sent to me when I hit a specific view that tries to create a new Referral model object.

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

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

As you can see, merely trying to instantiate a Referral model object triggers this exception. Here is the model in question:

如您所见,仅尝试实例化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

Is this a bug in Django or am I unknowingly doing something that I ought not? Anyone have any suggestions for fixes or workarounds?

这是Django中的一个错误还是我在不知不觉中做了一些我不应该做的事情?任何人有任何修复或解决方法的建议?

2 个解决方案

#1


13  

UPDATE (with solution below)

更新(以下解决方案)

I've been digging into the Django model code and it seems like there is a bug that creates a race condition when using "app.model"-based identifiers for the related field in a ForeignKey. When the application is running in production mode as opposed to DEBUG, the ForeignKey.get_default method referenced in the exception above tries to check if the provided default value is an instance of the related field (self.rel.to):

我一直在深入研究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

Initially when a ForeignKey is instantiated with a string-based related field, self.rel.to is set to the string-based identifier. There is a separate function in related.py called add_lazy_relation that, under normal circumstances, attempts to convert this string-based identifier into a model class reference. Because models are loaded in a lazy fashion, it's possible that this conversion can be deferred until the AppCache is fully loaded.

最初,当使用基于字符串的相关字段实例化ForeignKey时,self.rel.to将设置为基于字符串的标识符。在related.py中有一个名为add_lazy_relation的单独函数,在正常情况下,它会尝试将此基于字符串的标识符转换为模型类引用。由于模型是以惰性方式加载的,因此可能会延迟此转换,直到AppCache完全加载为止。

Therefore, if get_default is called on a string-based ForeignKey relation before AppCache is fully populated, it's possible for a TypeError exception to be raised. Apparently putting my application into production mode was enough to shift the timing of model caching that this error started occurring for me.

因此,如果在完全填充AppCache之前在基于字符串的ForeignKey关系上调用get_default,则可能会引发TypeError异常。显然我的应用程序进入生产模式足以改变模型缓存的时间,这个错误开始发生在我身上。

SOLUTION

It seems this is genuinely a bug in Django, but here's how to get around it if you do ever run into this problem. Add the following code snippet immediately before you instantiate a troublesome model:

看起来这真的是Django中的一个错误,但是如果遇到这个问题,这里就是如何绕过它。在实例化麻烦的模型之前立即添加以下代码段:

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

This checks the loaded flag on the AppCache to determine if the cache if fully populated. If it is not, we will force the cache to fully populate now. And the problem will be solved.

这将检查AppCache上的已加载标志,以确定缓存是否已完全填充。如果不是,我们将强制缓存现在完全填充。问题将得到解决。

#2


1  

Another cause:

另一个原因:

Make sure that all Foreign Keys are in the same reference models in the same application (app label). I was banging my head against the wall for a while on this one.

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

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

#1


13  

UPDATE (with solution below)

更新(以下解决方案)

I've been digging into the Django model code and it seems like there is a bug that creates a race condition when using "app.model"-based identifiers for the related field in a ForeignKey. When the application is running in production mode as opposed to DEBUG, the ForeignKey.get_default method referenced in the exception above tries to check if the provided default value is an instance of the related field (self.rel.to):

我一直在深入研究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

Initially when a ForeignKey is instantiated with a string-based related field, self.rel.to is set to the string-based identifier. There is a separate function in related.py called add_lazy_relation that, under normal circumstances, attempts to convert this string-based identifier into a model class reference. Because models are loaded in a lazy fashion, it's possible that this conversion can be deferred until the AppCache is fully loaded.

最初,当使用基于字符串的相关字段实例化ForeignKey时,self.rel.to将设置为基于字符串的标识符。在related.py中有一个名为add_lazy_relation的单独函数,在正常情况下,它会尝试将此基于字符串的标识符转换为模型类引用。由于模型是以惰性方式加载的,因此可能会延迟此转换,直到AppCache完全加载为止。

Therefore, if get_default is called on a string-based ForeignKey relation before AppCache is fully populated, it's possible for a TypeError exception to be raised. Apparently putting my application into production mode was enough to shift the timing of model caching that this error started occurring for me.

因此,如果在完全填充AppCache之前在基于字符串的ForeignKey关系上调用get_default,则可能会引发TypeError异常。显然我的应用程序进入生产模式足以改变模型缓存的时间,这个错误开始发生在我身上。

SOLUTION

It seems this is genuinely a bug in Django, but here's how to get around it if you do ever run into this problem. Add the following code snippet immediately before you instantiate a troublesome model:

看起来这真的是Django中的一个错误,但是如果遇到这个问题,这里就是如何绕过它。在实例化麻烦的模型之前立即添加以下代码段:

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

This checks the loaded flag on the AppCache to determine if the cache if fully populated. If it is not, we will force the cache to fully populate now. And the problem will be solved.

这将检查AppCache上的已加载标志,以确定缓存是否已完全填充。如果不是,我们将强制缓存现在完全填充。问题将得到解决。

#2


1  

Another cause:

另一个原因:

Make sure that all Foreign Keys are in the same reference models in the same application (app label). I was banging my head against the wall for a while on this one.

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

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