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

Django Admin页面实现Model查询集随选中Brand动态过滤

Django Admin中Year页面根据选中Brand动态过滤Model查询集

核心思路

Year模型通过Model间接关联Brand(Year → Model → Brand),要实现动态过滤需在Year的Admin页面新增临时Brand选择字段,通过前端JS实现无刷新更新Model下拉框,同时后端添加验证确保数据一致性。

步骤实现

1. 自定义Admin表单

添加临时Brand字段,初始化时根据实例设置默认值和Model查询集,并添加验证逻辑:

from django import forms
from .models import Brand, Model, Year

class YearAdminForm(forms.ModelForm):
    # 临时添加品牌选择字段,用于触发动态过滤
    brand = forms.ModelChoiceField(queryset=Brand.objects.all(), required=True)

    class Meta:
        model = Year
        fields = ['brand', 'model', 'year']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 编辑页面时,默认选中对应品牌并过滤型号
        if self.instance.pk:
            related_brand = self.instance.model.brand
            self.fields['brand'].initial = related_brand
            self.fields['model'].queryset = Model.objects.filter(brand=related_brand)
        else:
            # 新增页面默认隐藏型号选项
            self.fields['model'].queryset = Model.objects.none()

    def clean(self):
        cleaned_data = super().clean()
        selected_brand = cleaned_data.get('brand')
        selected_model = cleaned_data.get('model')
        # 验证型号是否属于选中品牌
        if selected_brand and selected_model and selected_model.brand != selected_brand:
            raise forms.ValidationError("所选型号不属于当前选中的品牌")
        return cleaned_data

2. 配置YearAdmin

指定自定义表单,并引入前端JS文件:

from django.contrib import admin
from .models import Year

class YearAdmin(admin.ModelAdmin):
    form = YearAdminForm

    # 引入自定义JS处理动态交互
    class Media:
        js = ('admin/js/year_admin_dynamic.js',)

admin.site.register(Year, YearAdmin)

3. 编写前端动态交互JS

在static/admin/js/year_admin_dynamic.js中实现品牌切换时的型号下拉更新:

document.addEventListener('DOMContentLoaded', function() {
    const brandSelect = document.getElementById('id_brand');
    const modelSelect = document.getElementById('id_model');

    // 监听品牌选择变化
    brandSelect.addEventListener('change', function() {
        const brandId = this.value;
        if (!brandId) {
            modelSelect.innerHTML = '';
            return;
        }
        // 异步请求获取对应品牌的型号列表
        fetch(`/admin/your_app/model/?brand_id=${brandId}`, {
            headers: {'X-Requested-With': 'XMLHttpRequest'}
        })
        .then(response => response.json())
        .then(models => {
            modelSelect.innerHTML = '';
            models.forEach(model => {
                const option = document.createElement('option');
                option.value = model.id;
                option.textContent = model.name;
                modelSelect.appendChild(option);
            });
        })
        .catch(error => console.error('加载型号列表失败:', error));
    });
});

注意:将your_app替换为你的Django应用名称。

4. 修改ModelAdmin返回JSON数据

让Model的Admin页面在接收到异步请求时,返回对应品牌的型号JSON列表:

from django.contrib import admin
from django.http import JsonResponse
from .models import Model

class ModelAdmin(admin.ModelAdmin):
    def changelist_view(self, request, extra_context=None):
        # 处理异步请求,返回型号JSON
        if 'brand_id' in request.GET and request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            brand_id = request.GET.get('brand_id')
            model_list = Model.objects.filter(brand_id=brand_id).values('id', 'name')
            return JsonResponse(list(model_list), safe=False)
        return super().changelist_view(request, extra_context)

admin.site.register(Model, ModelAdmin)

备用方案(页面刷新方式)

如果不需要无刷新交互,可以通过页面跳转传递参数实现过滤:

class YearAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'model':
            # 从GET参数获取品牌ID
            brand_id = request.GET.get('brand')
            if brand_id:
                kwargs['queryset'] = Model.objects.filter(brand_id=brand_id)
            # 编辑页面从实例获取品牌ID
            elif request.resolver_match.kwargs.get('object_id'):
                year_instance = Year.objects.get(id=request.resolver_match.kwargs['object_id'])
                kwargs['queryset'] = Model.objects.filter(brand=year_instance.model.brand)
            else:
                kwargs['queryset'] = Model.objects.none()
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

    def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
        # 新增页面传递品牌参数
        if object_id is None and 'brand' in request.GET:
            extra_context = extra_context or {}
            extra_context['brand_id'] = request.GET['brand']
        return super().changeform_view(request, object_id, form_url, extra_context)

这种方式需要用户选择品牌后手动刷新页面,或者通过修改Brand字段的跳转链接实现自动刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:30:56