Django Admin Actions — действия с промежуточной страницей

Привет. Полезная штука экшены в админке! Хочу поделиться как можно сделать экшен который после выбора элементов будет отправлять пользователя на промежуточную страницу чтобы с этими элементами можно было сделать что то особенное. Пример? Например у вас есть интернет магазин, таблица товаров. Вы хотите перенести часть товаров из одного раздела (книги) в другой (книги технические). Выбираем нужные книги, выбираем действие «Перенести в другой раздел», жмем применить, переходим на промежуточную страницу, выбираем нужный раздел и жмем сохранить. Здорово? Давайте попробуем.

Описываем форму:

class ChangeCategoryForm(forms.Form):
    _selected_action = forms.CharField(widget=forms.MultipleHiddenInput)
    category = forms.ModelChoiceField(queryset=Category.objects.all(), label=u'Основная категория')

Загадочное поле _select_action, да? Тут будут ID выбранных элементов. Django заберет их потом из POST запроса и сделает из них Queryset для которого мы будем делать наши действия (см. код ниже).

Наш экшен это как и всегда метод. Назовем его move_to_category.

def move_to_category(modeladmin, request, queryset):
       form = None

       if 'apply' in request.POST:
           form = ChangeCategoryForm(request.POST)

           if form.is_valid():
               category = form.cleaned_data['category']

               count = 0
               for item in queryset:
                   item.category = category
                   item.save()
                   count += 1

               modeladmin.message_user(request, "Категория %s применена к %d товарам." % (category, count))
               return HttpResponseRedirect(request.get_full_path())

       if not form:
           form = ChangeCategoryForm(initial={'_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME)})

       return render(request, 'catalog/move_to_category.html', {'items': queryset,'form': form, 'title':u'Изменение категории'})

move_to_category.short_description = u"Изменить категорию"

Объявляем экшен в класс ProductAdmin:

actions = [move_to_category,]

И создаем шаблон для показа всего этого

{% extends "admin/base_site.html" %}

{% block content %}
<form action="" method="post">{% csrf_token %}
    {{ form }}
    <p>Новая категория будет назначена для следующих позиций:</p>
    <ul>{{ items|unordered_list }}</ul>
    <input type="hidden" name="action" value="move_to_category" />
    <input type="submit" name="apply" value="Сохранить" />
</form>
{% endblock %}

Вот собственно и все. Подобным способом можно сделать очень очень очень много всяких важных, нужных и интересных вещей.

И напоследок хочу привести скриншоты с рабочего проекта которые показывают как все это работает.

image

image

image

image

Удачи!

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 9

    +2
    Гуд. Надо взять на вооружение.
      0
      Недавно нужно было такое сделать ) возьму на вооружение.
        0
        Выглядит интересно, правда я не совсем понял где это надо вписывать.
          0
          Все в файле admin.py, но форму желательно вынести в forms.py чтобы не было беспорядка в коде.
            0
            Спасибо за помощь, уже разобрался.
          0
          Это очень плохой способ — вы в _selected_action можете получить 400 тысяч объектов и у вас будет просто out of memory
            0
            Не подскажите как можно по другому сделать?
            0
            Почему-то не видно ссылки на источник:
            www.jpichon.net/blog/2010/08/django-admin-actions-and-intermediate-pages/
              0
              Вот тут небольшая ошибка вылезла
              form = ChangeCategoryForm(initial={'_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME)})
              


              Если элементов на странице 20, страниц больше 1 и хочется выбрать все, в админке есть кнопка «выбрать все( ххх штук)». При таком раскладе в форму передаются только объекты модели с 1й страницы, что бы передавались все сделал вот так:
              form = ActionsAddSaleForProduct(initial={'_selected_action': queryset.values_list('id', flat=True)})
              

              Only users with full accounts can post comments. Log in, please.