2

The problem

Suppose I have three classes A, B and C, where B is a subclass of A and C is a subclass of B:

A <- B <- C

When I open up the admin and list all "A"s, I see all "A"s, "B"s and "C"s. But when I follow one of those links, to see the details and edit that particular B, I will see only the fields of B, even if that instance is actually an instance of C. What I would like to see is the object to be shown to me according to its most specific type.

What I'm trying

I'm using InheritanceManager to get instances casted to the right type when working at a more abstract level. This works almost well (it can't handle more than one inheritance level). However, even for a single inheritance level, I can't get the polymorphic behavior to be reflected in the admin, as obviously the admin doesn't know about the manager's select_subclasses() method.

Any idea on how could I use to get such a polymorphic-like behavior on the admin?

Concrete Example

models.py:

from django.db import models
from model_utils.managers import InheritanceManager

class A(models.Model):
    a_field = models.CharField(max_length=200)
    objects = InheritanceManager()

class B(A):
    b_field = models.CharField(max_length=200)

class C(B):
    c_field = models.CharField(max_length=200)

admin.py

from myapp.models import A, B, C
from django.contrib import admin

admin.site.register(A)
admin.site.register(B)
admin.site.register(C)

Update

Adding a link to two threads from 2010 with some thoughts on how to achieve this with django-polymorphic:

Community
  • 1
  • 1
Filipe Correia
  • 5,415
  • 6
  • 32
  • 47

1 Answers1

3

This answer is partial, since I can't reproduce your first issue. When I list parent model objects, I see all of them. (Or maybe there's some misunderstanding.)


The issue with incomplete fields can be partially solved with admin inline. Since the subclass is simply a model with implicit OneToOneField to parent model, you can define an inline for "C" and then include it into inlines attribute on B's admin.

The problems are:

  • User won't be able to create object of class "C" via an inline in B's admin; it could be done only via C's admin. It's viewing only.
  • It won't work with multiple inheritance levels: you can include B into A's admin as an inline, but I know no easy way to include C as an inline to B's inline.

Another way is to modify A's admin template, placing there a link to the real instance (be it B or C). But I suppose you've already thought of it.


Regarding last issue: if you want to modify some model admin's queryset, it can be done via ModelAdmin's queryset() method (see an example in this question). You can override this method on your model's admin and place select_subclasses() logic there. But I haven't tried it so I can't say what would be ModelAdmin's behaviour if you do this. Maybe you'll need to override a few more methods.


PS. I currently use django-polymorphic, working on similar project with concrete inheritance. It doesn't provide any means to manage polymorphic models via admin either, so I decided not to rely much on Django's admin for this and just create a simple custom interface for site staff, I guess it won't take much time.

Community
  • 1
  • 1
Anton Strogonoff
  • 32,294
  • 8
  • 53
  • 61
  • I've added a concrete example to the question. You're right, listing all "A"s will also list "B"s and "C"s. I've also fixed the question accordingly and added a bit more detail to the remaining issue. – Filipe Correia May 05 '11 at 15:05
  • Thanks for the inlines suggestion. I can definitely work around some issues using them but, as you say, their applicability is quite limited, and the problems you raise are not negligible. The `queryset()` method works pretty well, but it also works only for a single level (that's more of a limitation of `InheritanceManager` though). – Filipe Correia May 05 '11 at 15:19
  • Of course, forgetting about the django-admin and just doing everything from scratch is also an option. I was seeing the "free" admin as one of the great benefits of django, but it's starting to look restrictive for this this project, as it will make extensive use of inheritance relations. – Filipe Correia May 05 '11 at 15:24
  • I think Django's admin is great, but the number of its use cases is limited, and documentation fails to note that. It appears at first that it's awesome and is really like an "admin" for your site, but actually it's more like a data browser (with its own limitations like generic relations and complex inheritance). And it's ok, since real "admin" use cases differ greatly from site to site. – Anton Strogonoff May 06 '11 at 07:22
  • For example, I use inlines and a link to real instance on parent instance's admin to handle inheritance at one project, and it's more than enough for *me*, while staff don't care (not dealing with that data directly). Also, it's the only project at the moment where I needed that kind of functionality, so I can't blame django developers for not implementing it (saving time to do bugfixes and more useful features). – Anton Strogonoff May 06 '11 at 07:28
  • 1
    It should be noted that [`django-polymorphic` now supports django's admin](https://django-polymorphic.readthedocs.io/en/stable/admin.html). – meshy Sep 03 '17 at 21:41