jgsogo
jgsogo

Reputation: 726

Django admin with multiple inlines of the same model

I'm having a problem with prefixes of StackedInlines in admin interface. I'll try to post all the necesary code.

models.py (brief)

##### Base classes

class BaseItem(models.Model):
    pass

class BaseProvider(PolymorphicModel):
   items = models.ManyToManyField(BaseItem, through="ItemProvided")

class ItemProvided(models.Model):
    item = models.ForeignKey(BaseItem)
    provider = models.ForeignKey(BaseProvider)
    price = models.IntegerField()

##### Implementing ones

class Hotel(BaseProvider):
    pass

class Room(BaseItem):
    pass

class Service(BaseItem):
    pass

This hierachy reads as follows: a hotel is a provider which can provide either rooms or services.

admin.py (brief)

#### Creating admin.StackedInline for Rooms

class RoomInlineFormSet(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        kwargs.update({'prefix':'room'})
        super(RoomInlineFormSet, self).__init__(*args, **kwargs)

class HotelRoomInline(admin.StackedInline):
    # This class also filters 'item' choiceField in order to have only ItemProvideds which are rooms
    model = ItemProvided
    formset = RoomInlineFormSet


#### Creating admin.StackedInline for Services

class ServiceInlineFormSet(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        kwargs.update({'prefix':'service'})
        super(ServiceInlineFormSet, self).__init__(*args, **kwargs)

class HotelServiceInline(admin.StackedInline):
    # This class also filters 'item' choiceField in order to have only ItemProvideds which are services
    model = ItemProvided
    formset = ServiceInlineFormSet


#### Adding inlines to HotelAdmin and model to admin interface

class HotelAdmin(admin.ModelAdmin):
    inlines = [
           HotelRoomInline,
           HotelServiceInline,
           ]

admin.site.register(Hotel, HotelAdmin)

With this code I managed to get two separated StackedInlines in admin interface for Hotel model, each of them allowing to select only the proper subset of itemprovideds. Great.

The problem: if a have one itemprovided created, in the room's StackedInline, for example; both StackedInlines are populated with the data... prefixes are not well managed...

Upvotes: 3

Views: 4783

Answers (1)

Mariusz Jamro
Mariusz Jamro

Reputation: 31633

A better solution than inlines with custom queryset is to use Proxy Models with custom manager which adds the default filtering. With that solution you can easily re-use those models outside of the admin:

# models.py

class HotelRoomManager(models.Manager):
    def get_query_set(self):
        return super(HotelRoomManager, self).get_query_set().filter(prefix='room')

class HotelRoom(ItemProvided):
    """ Only ItemProvided with prefix=room """
    objects = HotelRoomManager()

    class Meta:
        proxy = True

class HotelServiceManager(models.Manager):
    def get_query_set(self):
        return super(HotelServiceManager, self).get_query_set().filter(prefix='service')

class HotelService(ItemProvided):
    """ Only ItemProvided with prefix=service"""
    objects = HotelServiceManager()

    class Meta:
        proxy = True


#### admin.py

class HotelRoomInline(admin.StackedInline):
    model = HotelRoom

class HotelServiceInline(admin.StackedInline):
    model = HotelService

class HotelAdmin(admin.ModelAdmin):
    inlines = [
           HotelRoomInline,
           HotelServiceInline,
           ]

Upvotes: 4

Related Questions