我有一个现有的功能性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中的错误还是我在不知不觉中做了一些我不应该做的事情?任何人都有修复或解决方法的建议吗?
答案 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 上测试。