Условно встроенный в админку Django? - PullRequest
7 голосов
/ 27 июня 2010

Я пытаюсь найти способ отображения следующего RelativeInline, только если Person.is_member значение True.

Текущий admin.py:

class RelativeInline(admin.TabularInline):
    model = Relative
    fk_name = 'member'

class PersonAdmin(admin.ModelAdmin):
    inlines = [RelativeInline,]
    ordering = ('first_name',)
    list_filter = ('is_member',)
    search_fields = ('first_name', 'last_name',)
    date_hierarchy = 'member_date'
    list_display = ('first_name', 'last_name', 'is_member', 'member_date', 'photo')

admin.site.register(Person, PersonAdmin)

Единственный совет, который мне удалось найти, - это то, что я могу переопределить get_formset, но я не смог найти хороший пример,поэтому моя слабая попытка не сработала.

Вот моя неудачная попытка:

class RelativeInline(admin.TabularInline):
    model = Relative
    fk_name = 'member'

class PersonAdmin(admin.ModelAdmin):
    ordering = ('first_name',)
    list_filter = ('is_member',)
    search_fields = ('first_name', 'last_name',)
    date_hierarchy = 'member_date'
    list_display = ('first_name', 'last_name', 'is_member', 'member_date', 'photo')

    def get_formset(self, request, obj=None, **kwargs):
        if obj.is_member:
            inlines = [RelativeInline,]
        return super(PersonAdmin, self).get_formset(request, obj, **kwargs)

admin.site.register(Person, PersonAdmin)

Нет ошибок, сгенерированных этим кодом, но нет встроенного кода независимо от того, является ли Person.is_member Истинным или Ложным.


Обновление: друг предложил мне попробовать изменить:

inlines = [RelativeInline,]

на:

self.inlines = [RelativeInline,]

, но безрезультатно.Я также пытался:

PersonAdmin.inlines = [RelativeInline,]

, но результат был тот же - без ошибок, без встроенных.

Ответы [ 3 ]

3 голосов
/ 13 февраля 2012

Ваше оригинальное решение было довольно близко.Если вы посмотрите в django / contrib / admin / options.py вокруг строки 290, то увидите, что встроенные классы создаются при создании экземпляра администратора модели, после чего список inlines игнорируется.Поэтому установка этого списка позже в get_formsets () не имеет никакого эффекта.

Однако вы правы в том, что get_formsets () - это то, что нужно переопределить, чтобы сделать ваши inline-условия условными.Встроенные экземпляры содержатся в self.inline_instances, поэтому, чтобы отключить их в зависимости от объекта (например, я хочу скрыть конкретную строку в форме «добавить»), вы должны переопределить его следующим образом:

class MyAdmin(models.ModelAdmin):

    inlines = [MyInline, SomeOtherInline]

    def get_formsets(self, request, obj=None):
        for inline in self.inline_instances:
            if isinstance(inline, MyInline) and obj is None:
                continue
            yield inline.get_formset(request, obj)
1 голос
/ 27 июня 2010

Я решил изменить всю парадигму и решить мою проблему другим способом.Вместо того, чтобы иметь единого администратора для всех людей с условным встроенным сообщением, я решил:

  1. Переопределить набор запросов для фильтрации только для членов и сохранить RelativeInline с администратором для этой модели
  2. Создайте модель прокси и переопределите ее набор запросов, чтобы отфильтровать ее для не членов.Администратор для этой модели не включает RelativeInline.

В конце концов, я думаю, что это более чистый подход.Теперь члены могут быть сохранены, и родственники (не члены) могут быть добавлены в строке.NonMemberAdmin позволяет редактировать не членов.

models.py:

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    is_member = models.BooleanField()
    is_active = models.BooleanField(default=True)

    class Meta:
        verbose_name_plural = 'Members'
        ordering = ('first_name', 'last_name')

class PersonProxy(Person):
    class Meta:
        proxy = True
        verbose_name_plural = 'Non-Members'

class Relationship(models.Model):
    name = models.CharField(max_length=50)

class Relative(models.Model):
    member = models.ForeignKey(Person, related_name='relative_member')
    relative = models.ForeignKey(Person, related_name='relative_relative')
    relationship = models.ForeignKey(Relationship)

admin.py:

class RelativeInline(admin.TabularInline):
    model = Relative
    fk_name = 'member'


class MemberAdmin(admin.ModelAdmin):
    inlines = [RelativeInline,]
    ordering = ('first_name',)
    # list_filter = ('is_member',)
    search_fields = ('first_name', 'last_name',)
    # date_hierarchy = 'member_date'
    list_display = ('first_name', 'last_name', 'member_date')

    def queryset(self, request):
        return (super(MemberAdmin, self).queryset(request)
                .filter(is_member=True, is_active=True))


class NonMemberAdmin(admin.ModelAdmin):
    ordering = ('first_name',)
    search_fields = ('first_name', 'last_name',)
    list_display = ('first_name', 'last_name')

    def queryset(self, request):
        return (super(NonMemberAdmin, self).queryset(request)
                .filter(is_member=False, is_active=True))


admin.site.register(Person, MemberAdmin)
admin.site.register(PersonProxy, NonMemberAdmin)
0 голосов
/ 17 октября 2017

Я понимаю, что этот вопрос немного стар, и кодовая база немного изменилась;сейчас есть более понятный момент для переопределения: get_inline_instances.Вы можете сделать это:

class PersonAdmin(models.ModelAdmin):

inlines = [RelativeInline,]

def get_inline_instances(self, request, obj=None):
    to_return = super(MyAdmin, self).get_inline_instances(request, obj)
    #filter out the RelativeInlines if obj.is_member is false
    if not obj or not obj.is_member:
        to_return = [x for x in to_return if not isinstance(x,RelativeInline)]
    return to_return
...