无法调用ModelAdmin.change_view(),ManagementForm数据丢失

时间:2019-03-25 10:09:09

标签: python django

我正在编程一个显示事件的网站。每次发生的事件都是其自己的对象。由于许多事件都是重复性的,重新输入所有内容并更改日期很繁琐,因此我添加了一个事件发生器,以便用户可以设置名称,位置和时间,然后为它们选择一堆日期。使用这些属性可以生成哪些事件。

我已将事件发生器的表单集成到事件的管理页面的更改视图中。即使遇到了很多有害的类型错误和与类型相关的崩溃,我什至设法使其正常工作。 (我真的希望Django有类型提示。)

但是,如果提交的出现生成器表单无效,则Django无法正确显示更改视图。它因验证错误['ManagementForm data is missing or has been tampered with']而崩溃。我尝试查看痕迹,但无法弄清楚是什么原因造成的。我只是将无效表单传递为extra_context,以使页面向用户显示错误。

admin.py

class EventAdmin(admin.ModelAdmin):
    inlines = [OccurrenceInline]
    change_form_template = "admin/event_change_form.html"

    def change_view(self, request, object_id, form_url="", extra_context={}):
        extra_context["generator_form"] = extra_context.get(
            "generator_form",
            OccurrenceGeneratorForm(initial={"event": Event.objects.get(pk=object_id)}),
        )

        return super().change_view(request, object_id, form_url, extra_context)

    def get_urls(self):
        urls = super().get_urls()
        extra_urls = [path("<path:object_id>/generator/", self.generator_view)]
        return extra_urls + urls

    def generator_view(self, request, object_id, *args, **kwargs):
        if request.method == "POST":
            form = OccurrenceGeneratorForm(request.POST)
            if form.is_valid():
                self.generate_occurrences(form.cleaned_data)
            else:
                extra_context = {"generator_form": form}
                return self.change_view(request, object_id, extra_context=extra_context)

        return self.change_view(request, object_id)

    def generate_occurrences(self, data):
        Occurrence.objects.bulk_create(
            [
                Occurrence(
                    event=data["event"],
                    location=data["location"],
                    start_date=date,
                    start_time=data["start_time"],
                    duration_in_minutes=data["duration_in_minutes"],
                )
                for date in data["dates"]
            ]
        )

该模板是标准更改视图模板的复制粘贴,底部添加了我的自定义出现生成器表单。

templates/admin/event_change_form.html

{% extends "admin/change_form.html" %}
{% load i18n admin_urls static admin_modify %}

{% block content %}<div id="content-main">
    {% block object-tools %}
    {% if change %}{% if not is_popup %}
    <ul class="object-tools">
        {% block object-tools-items %}
        {% change_form_object_tools %}
        {% endblock %}
    </ul>
    {% endif %}{% endif %}
    {% endblock %}
    <form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post"
        id="{{ opts.model_name }}_form" novalidate>{% csrf_token %}{% block form_top %}{% endblock %}
        <div>
            {% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %}
            {% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %}
            {% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
            {% if errors %}
            <p class="errornote">
                {% if errors|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
            </p>
            {{ adminform.form.non_field_errors }}
            {% endif %}

            {% block field_sets %}
            {% for fieldset in adminform %}
            {% include "admin/includes/fieldset.html" %}
            {% endfor %}
            {% endblock %}

            {% block after_field_sets %}{% endblock %}

            {% block inline_field_sets %}
            {% for inline_admin_formset in inline_admin_formsets %}
            {% include inline_admin_formset.opts.template %}
            {% endfor %}
            {% endblock %}

            {% block after_related_objects %}{% endblock %}

            {% block submit_buttons_bottom %}{% submit_row %}{% endblock %}

            {% block admin_change_form_document_ready %}
            <script type="text/javascript" id="django-admin-form-add-constants"
                src="{% static 'admin/js/change_form.js' %}" {% if adminform and add %}
                data-model-name="{{ opts.model_name }}" {% endif %}>
                </script>
            {% endblock %}

            {# JavaScript for prepopulated fields #}
            {% prepopulated_fields_js %}

        </div>
    </form>

    <details style="margin-bottom: 30px; padding: 10px; border: 1px solid lightgray;">
        <summary>
            <h2 style="display: inline;">Occurrence Generator</h2>
        </summary>
        <div id="occurrence-generator" style="margin-top: 10px;">
            {{ generator_form.media }}
            <form method="post" action="../generator/">{% csrf_token %}
                {{ generator_form.as_p }}
                <input type="submit" value="Generator occurrences">
            </form>
        </div>
    </details>
</div>
{% endblock %}

这里是否有明显的地方我做错了?我真的不知道表单通常来自何处以及如何获取或提供表单。

0 个答案:

没有答案