Reputation: 726
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
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