属性错误:'NoneType'对象没有属性'attname'(Django)

19

我有一个相当复杂的模型,其中第一个调用MyModel.objects.create(**kwargs)会失败,显示以下内容:

AttributeError: 'NoneType' object has no attribute 'attname'

堆栈跟踪如下所示(在Django 1.11中)。

django/db/models/manager.py:85: in manager_method
   return getattr(self.get_queryset(), name)(*args, **kwargs)
django/db/models/query.py:394: in create
   obj.save(force_insert=True, using=self.db)
django/db/models/base.py:807: in save
   force_update=force_update, update_fields=update_fields)
django/db/models/base.py:837: in save_base
   updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
django/db/models/base.py:889: in _save_table
   pk_val = self._get_pk_val(meta)
django/db/models/base.py:644: in _get_pk_val
   return getattr(self, meta.pk.attname)
django/db/models/query_utils.py:114: in __get__
   val = self._check_parent_chain(instance, self.field_name)
django/db/models/query_utils.py:131: in __check_parent_chain
   return getattr(instance, link_field.attname)

对我来说,模型定义看起来没问题。我已经检查了create调用的所有参数都是我想要的。

我不想简化模型以找到问题,因为模型非常复杂。(我所有其他的模型,其中许多相似的模型似乎都工作良好。)

那么是什么导致了这个奇怪的消息呢?

6个回答

39

找到这个问题花了大约90分钟。在从我的模型中删除抽象超级模型、所有关系字段和除一个 IntegerField 之外的所有数据字段后,我才找到它。但是 create 仍然不起作用。

此时,我在完全相同的测试环境中调用了一些其他简单模型类 MyModel2 上的 create,它像惯常一样工作。

那么 MyModel 有什么特殊之处呢??

然后我想到了: MyModel 有一个 __init__ 方法;我的大多数其他模型都没有。所以看看那个。然后敲你的额头:我只是忘了必须使用(Python 3 风格的)

super().__init__(*args, **kwargs)

寓意: 不要忘记这个,否则你可能会遭受一个非常困难的错误消息。

(注意:如果您不喜欢这篇文章的风格,我很抱歉。这是我为了治疗而需要写作的。)


5

就我而言,我有:

 def __init__(self):
        return self.title

替代

 def __str__(self):
        return self.title

所以我错误地将 __init__ 写成了 __str__

3
嗨,Jafeth,很高兴你在这里。然而,这不是对问题的回答。如果有人给它投反对票,请不要感到惊讶或生气。(它适合作为评论,但添加评论需要比您当前拥有的1个积分更多的积分--在StackOverflow开始有点困难。) - Lutz Prechelt
我也遇到了同样的问题。PyCharm自动添加了__init__,但我没有注意到它 :-/ - joshlsullivan

1
重新表述并更加明确: 这个错误是由于一个没有引用其父类的__init__方法造成的。 确保您的__init__方法定义如下:
def __init__(self, *args, **kwargs):
    super().__init__(*args,**kwargs)
    ...

0
我遇到了这个错误,但是来自完全不同的用例。我最终通过从其__dict__表示中删除id属性,然后稍后尝试再次访问id属性,破坏了我的Django模型实例对象。解决方案:如果您计划在原始实例对象上稍后使用那些属性,请不要从Django模型实例的__dict__中删除项目。
instance1 = File.objects.get(path = '/path/to/sample1.txt')

print(instance1)
# /path/to/sample1.txt # this is my normal __str__ method for the model

# preview the instance dict representation
print(instance1.__dict__)
# {'_state': <django.db.models.base.ModelState object>, 'id': 7, 'path': '/path/to/sample1.txt'}

# create object to hold the dict
instance1_dict = instance1.__dict__

# remove 'id' for test case because its non-deterministic
instance1_dict.pop('id')

# check what the dict object looks like now
print(instance1_dict)
# {'_state': <django.db.models.base.ModelState object>, 'path': '/path/to/sample1.txt'}
# 'id' no longer present

# check what the original instance object dict representation looks like
print(instance1.__dict__)
# {'_state': <django.db.models.base.ModelState object>, 'path': '/path/to/sample1.txt'}
# 'id' is no longer present anymore

# try to access 'id' on the original instance object
expected_id = instance1.id
# AttributeError: 'NoneType' object has no attribute 'attname'

1
通常最好远离Django模型对象(或模型类)的内部,因为模型充满了奇怪的魔法。 - Lutz Prechelt

0
这更像是一条评论而不是解决方案,但是我声望不够高无法进行评论,所以只能这样写。在我们的情况下,问题出在我们在日志调用中使用了Python的f-strings,其中包含Django模型对象作为变量。这个问题可以100%重现。将f-strings替换为Python懒惰日志记录器推荐的字符串格式化方式(例如logger.info('Hello %s', name)而不是logger.info(f'Hello {name}')),问题就解决了。希望我能帮助某人节省数小时的故障排除时间。

0
这个错误可能发生在Django的代理模型继承中。例如,假设应用程序有一个普通的Django模型Report和从它继承的代理模型ReportExist。当另一个普通模型(ReportSelect)从代理模型继承时,就会出现错误。
class Report(models.Model):
   # normal model

class ReportExist(Report):
    class Meta:
        proxy = True

class ReportSelect(ReportExist):
   # no meta, error

proxy = True 添加到 ReportSelectMeta 类可以解决这个错误。
class ReportSelect(ReportExist):
   class Meta:
       proxy = True

   # no error

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接