Почему моя django-crispy AdminForm не может разрешить URL AdminSite?

Настройка

Я определил новый url администратора:

from django.contrib.admin import AdminSite
from django.http import HttpResponse
from django.urls import path

class MyAdminSite(AdminSite):

     def get_urls(self):
         from django.urls import path
         urls = super().get_urls()
         urls += [
            path(
                "generate",
                admin_site.admin_view(self.my_view),
                name="generate",
            )
         ]
         return urls

     def my_view(self, request):
        print(request.data)
        return HttpResponse("Hello!")

admin_site = MyAdminSite()

url успешно зарегистрирован:

print(admin_site.get_urls())
[ ..., ..., <URLPattern 'generate' [name='generate']>]   # <-- here!

Теперь в моем django-crispy-form мне нужно добавить действие формы для нескольких кнопок отправки. Библиотека не позволяет задавать несколько действий формы, поэтому мне пришлось отключить тег формы и добавить новый вручную:

class PromptForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.helper = FormHelper()          # django-crispy-forms
        self.helper.form_method = 'post'
        self.helper.form_tag = False        # <-- disable form_tag

        # Form layout 
        self.helper.layout = Layout(

            # Add new form_tag 
            HTML("""<form action="{% url 'admin:generate' %}"><input type="submit" class="btn btn-success" value="generate"></form>"""),
        )

Выпуск

Оба {% url 'generate' %} и {% url 'admin:generate' %} не могут установить обратное соответствие новому url:

`django.urls.exceptions.NoReverseMatch: Reverse for 'generate' not found. 'generate' is not a valid view function or pattern name.

Решение

Добавьте пользовательское действие к url /admin/.../change, переопределив django.contrib.admin.options.ModelAdmin._changeform_view:

from django.contrib import admin 

class MyModelAdmin(admin.ModelAdmin): 

    def _changeform_view(self, request, object_id, form_url, extra_context):

        if '<your-action>' in request: 
            # 1. check permissions
            # 2. do your thing 
            print(request)
        
        return super()._changeform_view(request, object_id, form_url, extra_context)

Теперь вы можете добавить простую кнопку sumbit в свою форму с помощью пользовательского действия:

<input type="submit" name="<your-action>" value="<button-title>">

Преимущество

  • Нулевой javascript.
  • Аутентификация защищена.
  • Все действия администратора будут работать с вашей формой (добавить, сохранить и продолжить, ...)
Вернуться на верх