6👍
<class 'app.admin.ChildAdmin'>: (admin.E108) The value of 'list_display[1]'
refers to 'name', which is not a callable, an attribute of 'ChildAdmin',
or an attribute or method on 'app.Child'.
The above is more than likely the error message that you are receiving. Abstract classes do not allow you to inherit instance attributes from the abstract class like that. It is looking for self.name
on the Child class, which does not exist.
The parts of the error we want to look at is:
…which is not a callable
Nope. It is not a callable, it is an attribute.
…an attribute of ‘ChildAdmin’,
Nope. It isn’t an attribute of the ChildAdmin
class.
…or an attribute or method on ‘app.Child’.
This is the part that is tripping you up. “What gives” is that it isn’t an attribute or method of the Child
class, but it is for the Parent
class.
What you want to do is:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
class Meta:
abstract = True
@property
def name(self):
return json.loads(self.json_dump)['name']
class Child(Parent):
magnitude = models.IntegerField()
Doing this will make the attribute available to the Child
class from parent. Alternatively, instead of using the @property
decorator, you could create a function definition called get_name
. I find the first to be simpler.
The caveat to this method is that it does not save the name at runtime. If you want to do that, you may want to consider Django’s signals to do a post_save hook to retrieve the name value and add a name = models.CharField(...)
to your model.
For clarification, Django does not support this. On startup, the following code runs a check on the list_display property:
def _check_list_display_item(self, cls, model, item, label):
"""
cls=<class 'app.admin.ChildAdmin'>
model=<class 'app.models.Child'>
item='name'
"""
# 'name' is not callable
if callable(item):
return []
# <class 'app.admin.ChildAdmin'> does not have the class attribute 'name'
elif hasattr(cls, item):
return []
# <class 'app.models.Child'> does not have the class attribute 'name'
elif hasattr(model, item):
...
else:
try:
# <class 'app.models.Child'>.Meta does not have a field called 'name'
model._meta.get_field(item)
except models.FieldDoesNotExist:
# This is where you end up.
return [
# This is a deliberate repeat of E108; there's more than one path
# required to test this condition.
checks.Error(
"The value of '%s' refers to '%s', which is not a callable, an attribute of '%s', or an attribute or method on '%s.%s'." % (
label, item, cls.__name__, model._meta.app_label, model._meta.object_name
),
hint=None,
obj=cls,
id='admin.E108',
)
]
As you can see, I have added comments to the code that is run to help you understand what is happening. You are right that the INSTANCE of Child
does have name, but that isn’t what Django is looking for. It’s looking for a class attribute, not instance attribute.
So, another way you can tackle this (you won’t like this, either) is by doing:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
name = ''
other_item = ''
this_too = ''
and_this = ''
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
super(Parent, self).__init__(*args, **kwargs)
setattr(self, 'name', json.loads(self.json_dump)['name'])
setattr(self, 'other_item', json.loads(self.json_dump)['other_item'])
setattr(self, 'this_too', json.loads(self.json_dump)['this_too'])
setattr(self, 'and_this', json.loads(self.json_dump)['and_this'])
This works. I just tested it. Django will find the attribute on the class.
0👍
As mentioned in doc, change Parent
model like this:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
def name(self):
return json.loads(self.json_dump)['name']
class Meta:
abstract = True
So name
attribute will be shown.
- [Django]-Chinese django translations not working
- [Django]-Django auto_add_now not working
- [Django]-Django: reverse parametrized url in JavaScript