如何在Django Admin中使用弹窗选择其他类及填充输入(参考Email addresses类)
嘿,我正好对Django Admin里的这类弹窗功能门儿清!你提到的两种场景——从其他模型类选内容、用弹窗填充输入框,其实都能通过Django自带的组件或者简单的自定义实现,咱们一步步来捋:
这种场景通常对应外键/多对多关系的选择,Django Admin自带了现成的组件,不用复杂自定义:
1. 外键关系的弹窗选择
假设你有一个UserProfile模型,关联了EmailAddress模型作为外键,要在UserProfile的Admin页面里通过弹窗选择Email地址,只需要在Admin配置里用raw_id_fields:
from django.contrib import admin from .models import UserProfile, EmailAddress class UserProfileAdmin(admin.ModelAdmin): # 这里指定外键字段,会显示输入框+放大镜图标 raw_id_fields = ('email_address',) admin.site.register(UserProfile, UserProfileAdmin) admin.site.register(EmailAddress)
效果就是:点击放大镜图标,会弹出EmailAddress的列表选择页面,选完之后自动把对应ID填充到外键输入框里,完全就是你说的那种弹窗选择效果。
2. 多对多关系的弹窗选择
如果是多对多关系,除了raw_id_fields,还可以用filter_horizontal/filter_vertical(不过这俩是左右选择框,如果你偏好弹窗的话还是用raw_id_fields):
class UserProfileAdmin(admin.ModelAdmin): # 多对多字段也可以用raw_id_fields,点击放大镜弹出选择弹窗 raw_id_fields = ('email_addresses',)
如果是想要点击按钮弹出窗口,输入内容后自动填充到当前表单的某个输入框(不是关联模型的选择,是自定义内容),就需要结合自定义模板和JavaScript来实现:
步骤1:自定义Admin的修改表单模板
在你的app下创建模板文件templates/admin/your_app/userprofile/change_form.html(路径要对应你的app和模型名),继承默认的Admin修改表单:
{% extends "admin/change_form.html" %} {% block extrahead %} {{ block.super }} <script> // 打开弹窗的函数 function openFillPopup() { // 弹窗大小可以自己调整 const popup = window.open('{% url "popup_fill" %}', 'fillPopup', 'width=600,height=400'); // 监听弹窗发来的消息,填充输入框 window.addEventListener('message', function(e) { // 验证消息来源,避免安全问题 if (e.origin === window.location.origin && e.data.type === 'fillInput') { document.getElementById('id_bio').value = e.data.value; } }); } </script> {% endblock %} {% block content %} {{ block.super }} <!-- 添加自定义按钮,触发弹窗 --> <button type="button" onclick="openFillPopup()" class="button">打开弹窗填充简介</button> {% endblock %}
步骤2:创建弹窗处理视图
在你的app的views.py里写一个处理弹窗逻辑的视图,记得加上管理员权限验证:
from django.contrib.admin.views.decorators import staff_member_required from django.shortcuts import render @staff_member_required def popup_fill_view(request): filled_value = '' if request.method == 'POST': # 获取弹窗中输入的内容 filled_value = request.POST.get('content', '') # 渲染弹窗模板,触发消息回传 return render(request, 'admin/your_app/popup_fill.html', {'filled_value': filled_value}) # GET请求时显示弹窗表单 return render(request, 'admin/your_app/popup_fill.html')
步骤3:创建弹窗的HTML模板
创建templates/admin/your_app/popup_fill.html:
<!DOCTYPE html> <html> <head> <title>填充内容</title> {% load static %} <link rel="stylesheet" href="{% static 'admin/css/base.css' %}"> </head> <body style="padding: 20px;"> <h3>输入要填充的内容</h3> <form method="post"> {% csrf_token %} <textarea name="content" rows="5" cols="50"></textarea> <br><br> <button type="submit" class="button">确认填充</button> </form> {% if filled_value %} <script> // 向父窗口发送消息,传递填充内容 window.opener.postMessage( {type: 'fillInput', value: '{{ filled_value|escapejs }}'}, window.location.origin ); // 关闭弹窗 window.close(); </script> {% endif %} </body> </html>
步骤4:配置弹窗的URL
在项目的urls.py里添加弹窗的URL路由:
from django.urls import path from your_app.views import popup_fill_view urlpatterns = [ # 其他Admin和项目URL... path('admin/popup-fill/', popup_fill_view, name='popup_fill'), ]
这样配置完之后,在UserProfile的Admin修改页面点击按钮,就会弹出一个输入窗口,输入内容提交后,自动填充到bio字段的输入框里啦!
内容的提问来源于stack exchange,提问作者tokhy2000

