Делаем inlines условными в админке Django - PullRequest
11 голосов
/ 24 марта 2011

У меня есть модель, которую сотрудники хотят редактировать до даты мероприятия.Например:

class ThingAdmin(admin.ModelAdmin):
    model = Thing

    if obj.date < today: #Something like that
        inlines = [MyInline,]

Проблема в том, что у меня нет доступа к экземпляру obj на этом уровнеЯ пытался переопределить get_formset (), но никуда не попал.

Ответы [ 8 ]

10 голосов
/ 24 марта 2011

Спасибо за комментарии для изменения в 1.4. Моя реализация здесь не была поточно-ориентированной, поэтому ее действительно следовало удалить.

Так как get_formsets передается объекту и вызывается get_inline_instances, мы можем изменить обе функции для воздействия на объект.

Это должно работать:

class ThingAdmin(admin.ModelAdmin):
    model = Thing

    inlines = [inline]
    other_set_of_inlines = [other_inline]

    def get_inline_instances(self, request, obj=None):
        #                                    ^^^ this is new
        inline_instances = []

        if obj.date > datetime.date(2012, 1, 1):
            inlines = self.inlines
        else:
            inlines = self.other_set_of_inlines

        for inline_class in inlines:
            inline = inline_class(self.model, self.admin_site)
            if request:
                if not (inline.has_add_permission(request) or
                        inline.has_change_permission(request) or
                        inline.has_delete_permission(request)):
                    continue
                if not inline.has_add_permission(request):
                    inline.max_num = 0
            inline_instances.append(inline)
        return inline_instances

    def get_formsets(self, request, obj=None):
        for inline in self.get_inline_instances(request, obj):
            #                                           ^^^^^ this is new
            yield inline.get_formset(request, obj)
3 голосов
/ 26 июля 2013

У меня был сложный случай, когда решения, которые я пробовал, неожиданно заканчивались неудачей (проблемы с полями только для чтения в строках).Это самый понятный и надежный способ, который я нашел:

class MyAdmin(admin.ModelAdmin):

    def add_view(self, request, form_url='', extra_context=None):
        self.inlines = [InlineA, InlineC]
        return super(MyAdmin, self).add_view(request, form_url, extra_context)

    def change_view(self, request, object_id, form_url='', extra_context=None):
        self.inlines = [InlineB, InlineC, InlineD]
        return super(MyAdmin, self).change_view(request, object_id, form_url, extra_context)

Это работает в Django 1.4.x.

2 голосов
/ 13 февраля 2013

В последней версии Django вам нужно переопределить ModelAdmin.get_formsets.например,

class MyAdmin(admin.ModelAdmin):

    def get_formsets(self, request, obj=None):
        if obj:
            for _ in super(MyAdmin, self).get_formsets(request, obj):
                yield _
        else:
            for inline in self.get_specific_inlines(request):
                yield inline.get_formset(request, obj)
0 голосов
/ 20 июня 2019

Начиная с Django 2.2.2 (текущая последняя версия на момент написания этой статьи), я бы использовал решение, предоставленное ранее @ aggieNick02, которое должно переопределить get_inline_instances, показанное ниже.

class ThingAdmin(models.ModelAdmin):
    inlines = [MyInline,]

    def get_inline_instances(self, request, obj=None):
        if not obj or obj.date >= today: return []
        return super(ThingAdmin, self).get_inline_instances(request, obj)

Я публикую этот новый ответ, потому что по состоянию на 17 апреля 2019 года в этом коммите похоже, что рекомендуемый в будущем способ сделать это - переопределить метод get_inlines. Поэтому в более поздних версиях решение этой проблемы может выглядеть как приведенный ниже код, который позволяет указывать различные наборы строк и использовать их в зависимости от условия.

class ThingAdmin(admin.ModelAdmin):
    model = Thing

    inlines = [inline]
    other_set_of_inlines = [other_inline]

    def get_inlines(self, request, obj):
        if obj.date > datetime.date(2012, 1, 1):
            return self.inlines
        else:
            return self.other_set_of_inlines
0 голосов
/ 17 октября 2017

Самый простой способ сделать это сейчас - переопределить и вызвать супер вызов get_inline_instances.

class ThingAdmin(models.ModelAdmin):
    inlines = [MyInline,]

    def get_inline_instances(self, request, obj=None):
        unfiltered = super(ThingAdmin, self).get_inline_instances(request, obj)
        #filter out the Inlines you don't want
        keep_myinline = obj and obj.date < today
        return [x for x in unfiltered if not isinstance(x,MyInline) or keep_myinline]

Это помещает MyInline, когда вы этого хотите, а не когда вы этого не хотите. Если вы знаете, что в вашем классе есть только встроенный объект MyInline, вы можете сделать его еще проще:

class ThingAdmin(models.ModelAdmin):
    inlines = [MyInline,]

    def get_inline_instances(self, request, obj=None):
        if not obj or obj.date >= today:
            return []
        return super(ThingAdmin, self).get_inline_instances(request, obj)
0 голосов
/ 16 января 2017

Я думаю, что самый простой способ взломать это - вызвать вашу пользовательскую функцию в get_fields или get_fieldsets и т. Д., Просто установите self.inlines в пользовательской функции.

class XXXAdmin(admin.ModelAdmin):
    def set_inlines(self, request, obj):
        """ hack inlines models according current request.user or obj """
        self.inlines = []
        if request.user.is_superuser or request.user is obj.recorder:
            self.inlines = [AbcInline, ]

    def get_fields(self, request, obj=None):
        self.set_inlines(request, obj)  # NOTICE this line
        super(XXXAdmin, self).get_fields(request, obj)
0 голосов
/ 15 июня 2016

Я думаю, что лучший ответ в документации django: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/

Поиск "get_inline_instances". Приведенный пример очень хорош, и нюансы вызова подробно описаны.

0 голосов
/ 15 июня 2014

У меня была ситуация, когда мне нужно было показать Inline, основанный на сайте администратора, на котором вы работали для данной истории.

Мне удалось получить динамические inline, работающие на Django 1.3, используя следующий код:

В основных моментах / admin.py

class HighlightInline(generic.GenericTabularInline):
    model = Highlight
    extra = 1
    max_num = 4
    fields = ('order', 'highlight')
    template = 'admin/highlights/inline.html'

class HighlightAdmin(admin.ModelAdmin):
    def regulate_highlight_inlines(self):
        highlights_enabled = Setting.objects.get_or_default('highlights_enabled', default='')
        highlight_inline_instance = HighlightInline(self.model, self.admin_site)
        highlight_found = any(isinstance(x, HighlightInline) for x in self.inline_instances)
        if highlights_enabled.strip().lower() == 'true':
            if not highlight_found:
                self.inline_instances.insert(0, highlight_inline_instance)
        else:
            if highlight_found:
                self.inline_instances.pop(0)
        print self.inline_instances

    def change_view(self, request, object_id, form_url='', extra_context=None):
        self.regulate_highlight_inlines()
        return super(HighlightAdmin, self).change_view(request, object_id)

    def add_view(self, request, form_url='', extra_context=None):
        self.regulate_highlight_inlines()   
        return super(HighlightAdmin, self).add_view(request, form_url, extra_context)

В истории / admin.py

class StoryAdmin(HighlightAdmin):

Одна вещьСледует отметить, что я не просто манипулирую встроенными классами (HighlightInline), но я изменяю встроенные экземпляры (HighlightInline (self.model, self.admin_site)).Это связано с тем, что django уже создал список встроенных экземпляров на основе списка встроенных классов во время первоначального создания класса admin.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...