You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Admin批量用户邮件动作失效:点击发送无响应排查

Django Admin自定义邮件动作故障排查

我基于CustomUser模型开发了一个Django Admin自定义动作,用来给选中的多个用户发送邮件。页面表面行为正常,但点击「Send Email」按钮后,直接回到Admin界面,控制台没有邮件发送记录,self.message_user的通知也没触发。

邮箱后端状态

密码重置功能可以正常把链接输出到控制台,说明EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"配置是有效的。

代码问题点

admin.py 核心问题

if "apply" in request.POST: 语句始终未执行:

class CustomUserAdmin(ExportMixin, UserAdmin):

    @admin.action(description="给选中用户发邮件")
    def send_email_action(self, request, queryset):
        print(request.POST)
        print(request.POST.getlist("apply"))
        input("HALT")
        if "apply" in request.POST:
            print("apply")
            form = EmailForm(request.POST)
            if form.is_valid():
                print("form valid")
                subject = form.cleaned_data["subject"]
                message = form.cleaned_data["message"]
                recipients = [user.email for user in queryset]
                send_mail(subject, message, "your_email@example.com", recipients)
                self.message_user(request, f"已发送 {len(recipients)} 封邮件。")
                return HttpResponseRedirect(request.get_full_path())
        else:
            print("no apply")
            form = EmailForm()
        return render(request, "email/admin_send.html", {"form": form})

forms.py 状态

EmailForm功能正常:

class EmailForm(forms.Form):
    subject = forms.CharField(max_length=256)
    message = forms.CharField(widget=forms.Textarea)

admin_send.html 疑似问题

  1. 点击「Send Email」后,send_email_action函数未被再次调用,可能与form action=""为空有关;
  2. 表单中input name="apply"的参数未传递到request对象中。
{% extends "base.html" %}
{% load crispy_forms_tags %}

{% block title %}
给用户发邮件
{% endblock %}

{% block content %}
<br>
<br>
<br>
<h2>给用户发邮件</h2>
<form action="" method="post">
    {% csrf_token %}
    {{ form|crispy }}
    <input type="submit" name="apply" value="Send Email">
</form>
{% endblock content %}

操作步骤与控制台输出

  1. 在Admin中选中多个CustomUser,选择「给选中用户发邮件」动作并点击GO:
<QueryDict: {'csrfmiddlewaretoken': ['zHlbmtRaNIFwrdNmCFxwyiVLi1IaCFKHoJAmZWKttwTMN97gC1JhWSryO9POuaDK'], 'action': ['send_email_action'], 'select_across': ['0'], 'index': ['0'], '_selected_action': ['6', '1', '7', '8']}>
[]
HALT
  1. 回车后表单显示,输入主题和消息:
no apply
[23/Nov/2024 23:58:25] "POST /admin/app_accounts/customuser/?company=Cisco HTTP/1.1" 200 10317
  1. 点击「Send Email」按钮:
[24/Nov/2024 00:02:07] "POST /admin/app_accounts/customuser/?company=Cisco HTTP/1.1" 200 19098
[24/Nov/2024 00:02:07] "GET /admin/jsi18n/ HTTP/1.1" 200 3342

疑问

Q1:是否需要设置form action?如果需要,应该配置什么值才能再次触发send_email_action函数?
Q2:如何确保input name="apply"的参数能被正确传递到request对象中?


解决方案

解决Q1:让表单提交触发动作函数

要让点击「发送邮件」时再次调用send_email_action,需要在表单中保留Admin动作的核心参数(action、_selected_action等),同时把表单的action设为当前Admin页面的完整路径。

修改admin_send.html,添加隐藏字段传递关键参数:

{% extends "base.html" %}
{% load crispy_forms_tags %}

{% block title %}
给用户发邮件
{% endblock %}

{% block content %}
<br>
<br>
<br>
<h2>给用户发邮件</h2>
<form action="{{ request.get_full_path }}" method="post">
    {% csrf_token %}
    <!-- 隐藏字段:传递Admin动作必要参数,确保触发send_email_action -->
    <input type="hidden" name="action" value="{{ request.POST.action }}">
    {% for user_id in request.POST._selected_action %}
        <input type="hidden" name="_selected_action" value="{{ user_id }}">
    {% endfor %}
    {% if request.POST.select_across %}
        <input type="hidden" name="select_across" value="{{ request.POST.select_across }}">
    {% endif %}
    {% if request.POST.index %}
        <input type="hidden" name="index" value="{{ request.POST.index }}">
    {% endif %}
    
    {{ form|crispy }}
    <input type="submit" name="apply" value="发送邮件">
</form>
{% endblock content %}

表单提交时,会把触发send_email_action所需的参数一起POST到Admin页面,Django Admin会自动调用对应的动作函数。

解决Q2:确保apply参数正确传递

只要表单method为post,且提交按钮的name="apply"无拼写错误,参数就会被包含在POST请求中。上述表单修改已满足条件,提交后request.POST中会出现apply键,if "apply" in request.POST:即可正常执行。

额外注意点

  • 无需手动处理查询集:第二次调用send_email_action时,Django Admin会根据_selected_action参数自动生成正确的queryset,直接使用即可;
  • 测试时可在send_email_action中打印request.POST,确认apply和其他参数是否存在。

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:23:15