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

如何在Django Admin中批量添加共享ref字段的Something模型实例

Django Admin实现批量添加共享字段的多实例

实现思路

通过自定义Admin表单、视图和模板,实现共享ref字段,动态添加多组name/is_active字段,最终批量创建模型实例。

步骤1:定义批量添加表单

创建自定义表单,包含共享的ref字段,以及根据配置动态生成的多组name和is_active字段:

# forms.py
from django import forms
from .models import Something, AnotherModel

class BulkSomethingForm(forms.Form):
    ref = forms.ModelChoiceField(queryset=AnotherModel.objects.all())
    num_entries = forms.IntegerField(widget=forms.HiddenInput(), initial=2)  # 默认显示2组条目

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 获取当前条目数量,默认2条
        num_entries = self.data.get('num_entries', self.fields['num_entries'].initial)
        try:
            num_entries = int(num_entries)
        except ValueError:
            num_entries = 2

        # 动态生成对应数量的name和is_active字段
        for i in range(num_entries):
            self.fields[f'name_{i}'] = forms.CharField(max_length=255)
            self.fields[f'is_active_{i}'] = forms.BooleanField(required=False, initial=True)

步骤2:自定义ModelAdmin

扩展Something的Admin类,添加批量添加的视图和入口:

# admin.py
from django.contrib import admin
from django.http import HttpResponseRedirect
from .models import Something
from .forms import BulkSomethingForm

@admin.register(Something)
class SomethingAdmin(admin.ModelAdmin):
    # 自定义列表页模板,添加批量添加按钮
    change_list_template = 'admin/something_change_list.html'

    def get_urls(self):
        from django.urls import path
        # 合并默认URL和自定义批量添加URL
        custom_urls = [
            path('bulk-add/', self.admin_site.admin_view(self.bulk_add_view), name='something_bulk_add'),
        ]
        return custom_urls + super().get_urls()

    def bulk_add_view(self, request):
        if request.method == 'POST':
            form = BulkSomethingForm(request.POST)
            if form.is_valid():
                ref_instance = form.cleaned_data['ref']
                num_entries = int(form.cleaned_data['num_entries'])
                # 批量创建Something实例
                for i in range(num_entries):
                    Something.objects.create(
                        ref=ref_instance,
                        name=form.cleaned_data[f'name_{i}'],
                        is_active=form.cleaned_data[f'is_active_{i}']
                    )
                self.message_user(request, f'成功创建{num_entries}条记录')
                # 跳转回列表页
                return HttpResponseRedirect('../')
        else:
            form = BulkSomethingForm()
        
        # 渲染批量添加页面
        return self.render_change_form(
            request, form, 
            title='批量添加Something', 
            template_name='admin/something_bulk_add.html'
        )

步骤3:创建自定义Admin模板

列表页模板(添加批量按钮)

在templates/admin/something_change_list.html中添加批量添加入口:

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

{% block object-tools %}
    <ul class="object-tools">
        <li>
            <a href="bulk-add/" class="addlink">批量添加Something</a>
        </li>
        {{ block.super }}
    </ul>
{% endblock %}

批量添加页面模板(支持动态添加字段)

创建templates/admin/something_bulk_add.html,实现动态添加字段组的功能:

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

{% block extrahead %}
    {{ block.super }}
    <script src="{% static 'admin/js/jquery.js' %}"></script>
    <script>
        $(document).ready(function() {
            let numEntries = parseInt($('#id_num_entries').val());

            // 点击按钮添加新的字段组
            $('#add-entry').click(function(e) {
                e.preventDefault();
                numEntries++;
                $('#id_num_entries').val(numEntries);

                // 插入新的name和is_active字段组
                const fieldGroup = `
                    <div class="form-row">
                        <div class="field-box">
                            <label for="id_name_${numEntries-1}">名称 ${numEntries}:</label>
                            <input type="text" name="name_${numEntries-1}" id="id_name_${numEntries-1}" maxlength="255" required>
                        </div>
                        <div class="field-box">
                            <label for="id_is_active_${numEntries-1}">是否激活:</label>
                            <input type="checkbox" name="is_active_${numEntries-1}" id="id_is_active_${numEntries-1}" checked>
                        </div>
                    </div>
                `;
                $('#entries-container').append(fieldGroup);
            });
        });
    </script>
{% endblock %}

{% block content %}
    <div id="content-main">
        <form method="post">
            {% csrf_token %}
            <!-- 共享的ref字段 -->
            <div class="form-row">
                {{ form.ref.label_tag }} {{ form.ref }}
            </div>
            <!-- 隐藏的条目数量字段 -->
            {{ form.num_entries }}
            <!-- 动态字段组容器 -->
            <div id="entries-container">
                {% for field in form %}
                    {% if field.name.startswith('name_') or field.name.startswith('is_active_') %}
                        {% if field.name.startswith('name_') %}
                            <div class="form-row">
                        {% endif %}
                        <div class="field-box">
                            {{ field.label_tag }} {{ field }}
                        </div>
                        {% if field.name.startswith('is_active_') %}
                            </div>
                        {% endif %}
                    {% endif %}
                {% endfor %}
            </div>
            <!-- 操作按钮 -->
            <div class="submit-row">
                <button type="button" id="add-entry">添加更多条目</button>
                <input type="submit" value="保存" class="default">
            </div>
        </form>
    </div>
{% endblock %}

功能说明

  • 在Something的Admin列表页,会新增一个「批量添加Something」的按钮
  • 点击进入批量添加页面后,只需选择一次ref值,默认显示2组name和is_active字段
  • 点击「添加更多条目」可动态增加字段组,填写完成后点击保存,系统会自动创建对应数量的Something实例,每个实例共享同一个ref值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 00:58:17