Here is models.py
:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
def __init__(self, *args, **kwargs):
super(Base, self).__init__(*args, **kwargs)
setattr(self, 'name', json.loads(self.json_dump)['name'])
class Meta:
abstract = True
class Child(Parent):
magnitude = models.IntegerField()
In my admin.py
I would like to configure the admin for Child to have the name
attribute displayed, so I have the following:
class ChildAdmin(admin.ModelAdmin):
model = Child
def get_list_display(self, request):
return ('id', 'name', 'magnitude')
admin.site.register(Child, ChildAdmin)
I have to have list_display
generated on the fly from the get_list_display
method because otherwise Django throws an error on startup complaining that name
is not defined in the Child
model. However, when running, name
should be available as it is set in the __init__
method whenever the object is instantiated from the database.
However, when I try to load the admin page I get the error:
Unable to lookup 'name' on Child or ChildAdmin
What gives?
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:
Nope. It is not a callable, it is an attribute.
Nope. It isn't an attribute of the
ChildAdmin
class.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 theParent
class.What you want to do is:
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 calledget_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:
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:
This works. I just tested it. Django will find the attribute on the class.
As mentioned in doc, change
Parent
model like this:So
name
attribute will be shown.