Фильтрация списка изменений администратора Django / ссылка на другие модели

У меня настроены модели следующим образом:

class ParentModel(models.Model):
    some_col = models.IntegerField()
    some_other = models.CharField()

class ChildModel(models.Model)
    parent = models.ForeignKey(ParentModel, related_name='children')

class ToyModel(models.Model)
    child_owner = models.ForeignKey(ChildModel, related_name='toys')

Теперь в моей панели администратора, когда я открываю список изменений для ParentModel, мне нужно новое поле/столбец в list_display со ссылкой для открытия списка изменений ChildModel, но с примененным фильтром для отображения только дочерних элементов из выбранного родителя. На данный момент я понял это с помощью этого метода, но я думаю, что есть более чистый способ сделать это, я просто не знаю, как это сделать:

class ParentAdmin(admin.ModelAdmin)
    list_display = ('id', 'some_col', 'some_other', 'list_children')
    def list_children(self, obj):
        url = urlresolvers.reverse('admin:appname_childmodel_changelist')
        return '<a href="{0}?parent__id__exact={1}">List children</a>'.format(url, obj.id)
    list_children.allow_tags = True
    list_children.short_description = 'Children'        

admin.site.register(Parent, ParentAdmin)

Итак, мой вопрос: можно ли добиться того же без этого «взлома ссылок»? Также можно ли в отдельной колонке в списке изменений ParentModel указать, есть ли у кого-то из его детей игрушки?


person Gordon Freeman    schedule 18.12.2011    source источник


Ответы (1)


Я думаю, что ваш подход к отображению столбца list_children правильный. Не беспокойтесь о «взломе ссылок», это нормально.

Чтобы отобразить столбец, указывающий, есть ли у кого-либо из дочерних объектов игрушки, просто определите другой метод в классе ParentAdmin и добавьте его в list_display, как и раньше.

class ParentAdmin(admin.ModelAdmin):
    list_display = ('id', 'some_col', 'some_other', 'list_children', 'children_has_toys')
    ...
    def children_has_toys(self, obj):
        """
        Returns 'yes' if any of the object's children has toys, otherwise 'no'
        """
        return ToyModel.objects.filter(child_owner__parent=obj).exists()
    children_has_toys.boolean = True

Установка boolean=True означает, что Django будет отображать значки «включено» или «выключено», как и для логических полей. Обратите внимание, что для этого подхода требуется один запрос для каждого родителя (т. е. O (n)). Вам нужно будет протестировать, чтобы увидеть, получаете ли вы приемлемую производительность в производственной среде.

person Alasdair    schedule 18.12.2011
comment
Спасибо за ваш ответ, он действительно мне очень помог. Я удивлен, что у django нет более элегантного способа ссылки на список изменений. В любом случае спасибо, ваша помощь решила теперь все мои проблемы. - person Gordon Freeman; 18.12.2011