Приложение администратора Django: создание динамического списка действий администратора - PullRequest
3 голосов
/ 14 декабря 2009

Я пытаюсь динамически создать список действий администратора, используя метод get_actions() для ModelAdmin. Каждое действие относится к конкретному экземпляру другой модели, и, поскольку новые экземпляры могут быть добавлены или удалены, я хочу убедиться, что список действий отражает это.

Вот это ModelAdmin:

class PackageAdmin(admin.ModelAdmin):
    list_display = ('name', 'quality')

    def _actions(self, request):
        for q in models.Quality.objects.all():
            action = lambda modeladmin, req, qset: qset.update(quality=q)
            name = "mark_%s" % (q,)
            yield (name, (action, name, "Mark selected as %s quality" % (q,)))

    def get_actions(self, request):
        return dict(action for action in self._actions(request))

(Странное повторяющееся указание возвращаемого значения кортежей объясняется документами Django для get_actions().)

Как и следовало ожидать, это приводит к списку действий администратора с соответствующим названием для массового назначения Quality внешних ключей для Package объектов.

Проблема в том, что какое бы действие я ни выбрал, один и тот же объект Quality назначается выбранным Package s.

Я предполагаю, что все замыкания, которые я создаю с ключевым словом lambda, содержат ссылку на один и тот же объект q, поэтому каждая итерация меняет значение q для каждой функции .

Могу ли я разорвать эту ссылку, позволяя мне по-прежнему использовать список замыканий, содержащих различные значения q?


Редактировать: я понимаю, что lambda не является необходимым в этом примере. Вместо:

action = lambda modeladmin, req, qset: qset.update(quality=q)

Я мог бы просто использовать def:

def action(modeladmin, req, qset):
    return qset.update(quality=q)

Ответы [ 3 ]

5 голосов
/ 14 декабря 2009

попробуй

   def make_action(quality):
        return lambda modeladmin, req, qset: qset.update(quality=quality)

   for q in models.Quality.objects.all():
       action = make_action(q)
       name = "mark_%s" % (q,)
       yield (name, (action, name, "Mark selected as %s quality" % (q,)))

если это не сработает, я подозреваю, что ошибка связана с использованием yield. может быть попробовать:

def make_action(quality):
    name = 'mark_%s' % quality
    action = lambda modeladmin, req, qset: qset.update(quality=quality)
    return (name, (action, name, "Mark selected as %s quality" % quality))

def get_actions(self, request):
    return dict([make_action for q in models.Quality.objects.all()])
1 голос
/ 14 декабря 2009

Как я уже упоминал в своем комментарии к ответу andylei, я только что нашел решение; использование другой функции для создания замыкания, похоже, нарушает ссылку, а это означает, что теперь каждое действие ссылается на правильный экземпляр Quality.

def create_action(quality):
    fun = lambda modeladmin, request, queryset: queryset.update(quality=quality)
    name = "mark_%s" % (quality,)
    return (name, (fun, name, "Mark selected as %s quality" % (quality,)))

class PackageAdmin(admin.ModelAdmin):
    list_display = ('name', 'quality')

    def get_actions(self, request):
        return dict(create_action(q) for q in models.Quality.objects.all())
0 голосов
/ 14 декабря 2009

Я удивлен, что q остается одним и тем же объектом в цикле.

Работает ли с quality=q.id в вашей лямбде?

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