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

如何在Django Admin中根据资助方选择限制方案下拉选项?

实现方案:Project Admin表单中按选中资助方过滤方案选项

完全可以实现这个需求,核心是通过后端QuerySet过滤对应资助方的方案,结合前端JavaScript监听资助方选择事件,动态更新方案下拉框的可选范围。以下是具体实现步骤:

1. 修正Model中的错误

首先修复你的Model代码里的两处问题:

# models.py
class Funder(models.Model):
    name = models.CharField(max_length=200)
    scheme = models.ManyToManyField('Scheme', blank=True)
    
class Scheme(models.Model):
    name = models.CharField(max_length=200)  # 移除多余的右括号

class Project(models.Model):
    title = models.CharField(max_length=200)
    funder = models.ForeignKey(Funder, on_delete=models.CASCADE)  # 必须指定on_delete
    scheme = models.ForeignKey(Scheme, on_delete=models.SET_NULL, null=True)  # SET_NULL需要配合null=True

2. 编写AJAX接口返回过滤后的方案列表

创建一个视图,根据传入的资助方ID返回其关联的方案:

# views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse
from django.views.generic import View
from .models import Funder

class SchemeAutocompleteView(LoginRequiredMixin, View):
    def get(self, request, *args, **kwargs):
        funder_id = request.GET.get('funder_id')
        schemes = []
        if funder_id:
            try:
                funder = Funder.objects.get(id=funder_id)
                # 用QuerySet过滤当前资助方关联的方案
                schemes = funder.scheme.all().values('id', 'name')
            except Funder.DoesNotExist:
                pass
        return JsonResponse(list(schemes), safe=False)

在urls.py中配置该接口的路由:

# urls.py
from django.urls import path
from .views import SchemeAutocompleteView

urlpatterns = [
    # 其他路由...
    path('scheme-autocomplete/', SchemeAutocompleteView.as_view(), name='scheme-autocomplete'),
]

3. 自定义Project Admin表单与逻辑

修改admin.py,自定义Project的Admin表单和ModelAdmin,引入前端JS实现动态更新:

# admin.py
from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from django import forms
from django.urls import reverse
from .models import Funder, Scheme, Project

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = '__all__'
        widgets = {
            'scheme': forms.Select(attrs={'id': 'id_scheme'}),
            'funder': forms.Select(attrs={'id': 'id_funder'}),
        }

class ProjectAdmin(admin.ModelAdmin):
    form = ProjectForm
    list_display = ('title', 'funder', 'scheme')
    
    def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
        extra_context = extra_context or {}
        # 传递AJAX接口URL到模板
        extra_context['scheme_autocomplete_url'] = reverse('scheme-autocomplete')
        return super().changeform_view(request, object_id, form_url, extra_context)
    
    # 引入自定义JS文件
    class Media:
        js = ('admin/js/project_scheme_filter.js',)

# 注册现有Admin
class FunderAdmin(ImportExportModelAdmin):
    search_fields = ['name',]
    autocomplete_fields = ['scheme']
    list_display = ("name",)

admin.site.register(Funder, FunderAdmin)
admin.site.register(Scheme)
admin.site.register(Project, ProjectAdmin)

4. 编写前端JS实现动态过滤

在项目的静态文件目录下创建admin/js/project_scheme_filter.js,监听资助方选择事件并更新方案下拉框:

document.addEventListener('DOMContentLoaded', function() {
    const funderSelect = document.getElementById('id_funder');
    const schemeSelect = document.getElementById('id_scheme');
    // 从模板获取AJAX接口URL
    const autocompleteUrl = "{{ scheme_autocomplete_url }}";

    // 根据资助方ID更新方案选项
    function updateSchemes(funderId) {
        fetch(`${autocompleteUrl}?funder_id=${funderId}`)
            .then(response => response.json())
            .then(data => {
                // 清空现有选项
                schemeSelect.innerHTML = '<option value="">---------</option>';
                // 添加过滤后的方案选项
                data.forEach(scheme => {
                    const option = document.createElement('option');
                    option.value = scheme.id;
                    option.textContent = scheme.name;
                    schemeSelect.appendChild(option);
                });
            });
    }

    // 监听资助方选择变化
    funderSelect.addEventListener('change', function() {
        updateSchemes(this.value);
    });

    // 编辑页面初始化时,加载当前资助方的方案
    if (funderSelect.value) {
        updateSchemes(funderSelect.value);
    }
});

5. 自定义Admin模板传递URL变量

在项目的templates目录下创建admin/[你的app名]/project/change_form.html,继承默认Admin模板并传递URL变量:

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

{% block extrahead %}
    {{ block.super }}
    <script>
        // 将模板变量转换为JS变量
        const scheme_autocomplete_url = "{{ scheme_autocomplete_url }}";
    </script>
{% endblock %}

核心逻辑说明

  • 后端通过funder.scheme.all()这个QuerySet精准过滤出当前资助方关联的所有方案,完全符合你的需求。
  • 前端通过监听资助方选择框的change事件,实时发送AJAX请求获取过滤后的方案列表,动态更新下拉选项。
  • 编辑页面初始化时会自动加载当前项目关联资助方的方案,保持数据一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 07:43:18