# Admin presentation for different types of the same model or is the Inheritance needed ?

**URL:** <https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493>\
**Category:** Using Django\
**Created:** [September 24, 2020, 10:28am UTC](https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493 "2020-09-24T10:28:16Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![pitagora04](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pitagora04/32/1019_2.png) [@pitagora04](https://forum.djangoproject.com/u/pitagora04)\
**Post date:** [September 24, 2020, 10:28am UTC](https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493/1 "2020-09-24T10:28:16Z")

</div>

Hi there,  
I have very very simple store with only `AudioProduct`. The model (simplified version) is here:

```auto
class AudioProduct(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, null=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    audio_path = models.FileField(upload_to='audiofiles/', blank=True, null=True)
    duration = models.IntegerField()

```

Now I have to extend this “store” to cover also `PaintingProduct` (I know, I was naive to trust the user that only audio will be used forever and ever).  
When speaking of ORM, I’m very afraid of using model inheritance so I prefer to use `type` field and put everything in one DB table with different fields NULLABLE.

So my idea is to have this:

```auto
PRODUCT_TYPES = (
    ('A', 'Audio'),
    ('P', 'Painting'),
)

class Product(models.Model):
    product_type = models.CharField(max_length=1, choices=PRODUCT_TYPES)
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, null=True)
    # AUDIO specific attributes
    price = models.DecimalField(max_digits=10, decimal_places=2,blank=True, null=True)
    audio_path = models.FileField(upload_to='audiofiles/', blank=True, null=True)
    # PAINTING specific attributes
    painting_technique = models.CharField(max_length=50,blank=True, null=True)
    thumbnail_image = models.FileField(upload_to='imagefiles/', blank=True, null=True)

```

**But here comes the problem - I kind of need to separate the Admin presentation for Audio and Painting - or at least I need 2 different ADD and CHANGE pages based on the Product type ?**  
For example, I want to have `Add Audio Product` and `Add Painting Product` pages separetely to show only the needed fields.  
Is that possible to achieve or do I need to go with inheritance ?

Thank you.  
Hrvoje

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 24, 2020, 1:05pm UTC](https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493/2 "2020-09-24T13:05:14Z")

</div>

This can be done, but you might run into some odd behavior.

You could create [Proxy models](https://docs.djangoproject.com/en/3.1/topics/db/models/#proxy-models), one for each of your audio and painting types.

Register each of them in the admin with a custom admin class only showing the required fields for that type.

Do not show the product\_type field to prevent confusion.

Override the get\_queryset in the ModelAdmin class to only return instances of that type.

Override the save methods on the proxy models to set the product\_type on an Add. (You may also want to have it null out the fields for the other type.)

(I think that covers most of it - there might be more that you would want to do depending upon your specific needs. Note, I am suggesting adding two proxy models in addition to having an interface for the Product model directly to ensure you still have some facility to clean up any models that might have gotten messed-up - having data in both sections.)

Ken

---

<div class="post-metadata">

**Author:** ![pitagora04](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pitagora04/32/1019_2.png) [@pitagora04](https://forum.djangoproject.com/u/pitagora04)\
**Post date:** [May 17, 2021, 5:12am UTC](https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493/3 "2021-05-17T05:12:13Z")

</div>

I registered `ProductAudioAdmin` and `ProductPaintingAdmin` and as a result I had 2 “sections” in Django Admin - one is for viewing/editing `ProductPainting` and one for viewing/editing `ProductAudio`.

Now I also registered parent `ProductAdmin` and in this page I see all products. But when I want to edit (or add) product, then all fields are shown. **Is it possible that Django Admin sees the difference between existing products and show only needed fields when I want to edit product ?**

```auto
class ProductAdmin(admin.ModelAdmin):
    # ...

class ProductAudioAdmin(ProductAdmin):
    fields = ['name','audio_duration_minutes']
    class Meta:
        proxy = True

class ProductPaintingAdmin(ProductAdmin):
    fields = ['name','painting_technique','painting_size']
    class Meta:
        proxy = True

```

---

<div class="post-metadata">

**Author:** ![pitagora04](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pitagora04/32/1019_2.png) [@pitagora04](https://forum.djangoproject.com/u/pitagora04)\
**Post date:** [May 17, 2021, 6:57am UTC](https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493/4 "2021-05-17T06:57:14Z")

</div>

Ok, I used `get_fields` to control which fields to show on CHANGE page:

```auto
class ProductAdmin(admin.ModelAdmin):
    readonly_fields = ['created_at','updated_at']
    def get_fields(self, request, obj=None):
        if obj:
            if obj.product_type == 'a':
                return [...]
            if obj.product_type == 'p':
                return [...]

```

This works perfect for changing existing products.

**Now I have to find a way to have different ADD actions** (it would be perfect to have 2 buttons `ADD Audio Product` and `ADD Painting Product` and then pre-define `product_type` based on which button was clicked).

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [May 17, 2021, 12:12pm UTC](https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493/5 "2021-05-17T12:12:04Z")

</div>

Extracted from the [Django documentation for the admin site](https://docs.djangoproject.com/en/3.2/ref/contrib/admin/):

> The admin’s recommended use is limited to an organization’s internal management tool. It’s not intended for building your entire front end around.  
> …  
> If you need to provide a more process-centric interface that abstracts away the implementation details of database tables and fields, then **it’s probably time to write your own views**.

(Emphasis added)

You may still be fine now - but as you keep adding more type-specific features to your process, you’re creating more work for yourself. You will eventually reach a point where you’re expending more effort making things work in the admin than if you just created your own views.

Now, aside from that, you _do_ have different add actions. You can select add from the model type chosen. You can then add a custom [save\_model](https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model) method in your ModelAdmin class to set the product\_type.

---

<div class="post-metadata">

**Author:** ![pitagora04](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pitagora04/32/1019_2.png) [@pitagora04](https://forum.djangoproject.com/u/pitagora04)\
**Post date:** [May 21, 2021, 9:26am UTC](https://forum.djangoproject.com/t/admin-presentation-for-different-types-of-the-same-model-or-is-the-inheritance-needed/4493/6 "2021-05-21T09:26:10Z")

</div>

@KenWhitesell thank you. All you said is true. But for I now I still find Django Admin feasible 🙂. Yes, there are sometimes tricky parts but somehow there is always a workaround which I can agree to at the end - as it is said Django is for developers with deadlines.

In this specific case at the end I decided to have 2 steps. In first step you decide for the `product_type` and then in the next step (when you edit the article) the additional fields will be shown based on `product_type` which works quite nice.

So I added `else` part to `get_fields()`

```auto
    def get_fields(self, request, obj=None):
        if obj:
            if obj.product_type == 'a':
                return [...]
            if obj.product_type == 'p':
                return [...]
        else: # in case of creating new article
            return ['title','template_type', ...]

```
