Django 3.2: AttributeError: объект 'NoneType' не имеет атрибута 'attname'
Я работаю с Django 3.2 и столкнулся с проблемой, на которую, кажется, есть ответы здесь и здесь также, и я попробовал решения, предложенные в принятых ответах, но не смог решить проблему, которая у меня возникла (сообщение об ошибке в заголовке темы).
Вот как выглядят мои модели:
#### models.py
class ActionableModel:
def __init__(self, parent_object):
self.parent = parent_object
# FIX: This might be an expensive operation ... need to investigate
if isinstance(parent_object, django.contrib.auth.get_user_model()):
self.owner = parent_object
self.actionable_object = parent_object
else:
self.owner = self.parent.get_owner()
self.actionable_object = self.parent.get_actionable_object()
self.owner_id = self.owner.id
self.ct = ContentType.objects.get_for_model(self.actionable_object)
self.object_id = self.actionable_object.id
# ...
class Prey(models.Model):
# ... fields
pass
class Predator(models.Model, ActionableModel):
catches = GenericRelation(Prey)
catch_count = models.PositiveIntegerField(default=0, db_index=True)
last_catch = models.DateTimeField(editable=False, blank=True, null=True, default=None)
def __init__(self, *args, **kwargs):
ActionableModel.__init__(self, *args, **kwargs)
# ...
class Meta:
abstract = True
# Classes used for testing - naming similar to [mommy](https://model-mommy.readthedocs.io/en/latest/basic_usage.html)
class Daddy():
def __init__(self, *args, **kwargs):
ActionableModel.__init__(self, *args, **kwargs)
class Foo(Daddy, Predator):
# ...
pass
В оболочке я набираю следующее:
from myapp.models import Foo
admin = django.contrib.auth.get_user_model().objects.all().first()
foo = Foo.objects.create(parent_object=admin)
Вот трассировка стека ошибки, которая приводит к заголовку темы:
Foo.objects.create(parent_object=admin)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/query.py", line 453, in create
obj.save(force_insert=True, using=self.db)
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/base.py", line 726, in save
self.save_base(using=using, force_insert=force_insert,
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/base.py", line 763, in save_base
updated = self._save_table(
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/base.py", line 822, in _save_table
pk_val = self._get_pk_val(meta)
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/base.py", line 575, in _get_pk_val
return getattr(self, meta.pk.attname)
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/query_utils.py", line 148, in __get__
val = self._check_parent_chain(instance)
File "/path/to/myapp/env/lib/python3.8/site-packages/django/db/models/query_utils.py", line 164, in _check_parent_chain
return getattr(instance, link_field.attname)
AttributeError: 'NoneType' object has no attribute 'attname'
Что вызывает эту ошибку, и как я могу ее устранить?
Проблема, похоже, заключается в том, что метод __init__ из класса django Model никогда не вызывается. Это происходит потому, что метод __init__ определен в вашем производном классе, но метод super() не вызывается явно.
Необходимо две вещи:
- Установка цепочки вызовов
super. - Обеспечение порядка разрешения методов позволяет цепочке
superдойти до методаModel.__init__. На практике это означает, чтоmodels.Modelдолжен наследоваться последним в производных классах, потому что вsuperнет ни одногоModel.__init__вызова.
Применяя эти пункты к предоставленному исходному коду:
class ActionableModel:
def __init__(self, *args, **kwargs):
# need to call super here
super().__init__(*args, **kwargs)
parent_object, = args
self.parent = parent_object
...
class Prey(models.Model):
pass
# note the change in derivation order.
class Predator(ActionableModel, models.Model):
catches = GenericRelation(Prey)
...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class Daddy:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class Foo(Daddy, Predator):
pass