如何用django-autocomplete-light和django-hacker实现Django Admin级联下拉?
问题描述
- 现有三个关联模型:
university(大学)、Course(课程)、enquiry(咨询),关联关系为enquiry→Course→university - 添加
enquiry数据时,希望course_interested字段仅显示与所选university_interested关联的有效课程(即Active=True的课程) - 尝试过
django-smart-select但未成功,不熟悉jQuery和Ajax,需要可行的实现方案
用户提供的models.py代码:
class university(models.Model): univ_name = models.CharField(max_length=100) country = CountryField(blank=True, null=True) univ_desc = models.CharField(max_length=1000) univ_logo = models.ImageField(upload_to="media") univ_phone = models.CharField(max_length=10, blank=True) univ_email = models.EmailField(max_length=254, blank=True) univ_website = models.URLField(blank=True) assigned_users = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, default="") def __str__(self): return self.univ_name class Meta: verbose_name_plural = "Universities" class Course(models.Model): university = models.ForeignKey(university, on_delete=models.CASCADE) course_name = models.CharField(max_length=100) course_levels = models.ForeignKey(course_levels, on_delete=models.CASCADE) intake = models.ForeignKey(intake, on_delete=models.CASCADE) documents_required = models.ForeignKey(documents_required, on_delete=models.CASCADE) course_requirements = models.ForeignKey(course_requirements, on_delete=models.CASCADE) Active = models.BooleanField() def __str__(self): return self.course_name class enquiry(models.Model): student_name = models.CharField(max_length=100) student_phone = models.CharField(max_length=10) student_email = models.EmailField() student_address = models.TextField() current_education = models.ForeignKey(current_education, on_delete=models.CASCADE) country_interested = CountryField(blank=True, null=True) university_interested = models.ForeignKey(university, on_delete=models.CASCADE) course_interested = models.ForeignKey(Course, on_delete=models.CASCADE, limit_choices_to={'Active':True}) level_applying_for = models.ForeignKey(course_levels, on_delete=models.CASCADE) intake_interested = models.ForeignKey(intake, on_delete=models.CASCADE) assigned_users = models.ForeignKey(User, on_delete=models.CASCADE, default="", limit_choices_to={"is_active": True}) enquiry_status = models.ForeignKey(enquiry_status, on_delete=models.CASCADE, default="") course_interested= ChainedForeignKey(Course,chained_field= 'university_interested',chained_model_field= 'university',show_all= False,auto_choose= True,sort=True,limit_choices_to = {"Active": True},)
解决方案
第一步:修复模型字段重复问题
你的enquiry模型中重复定义了course_interested字段,删除原ForeignKey定义,仅保留ChainedForeignKey:
class enquiry(models.Model): # 保留其他所有字段 university_interested = models.ForeignKey(university, on_delete=models.CASCADE) # 移除这一行:course_interested = models.ForeignKey(Course, on_delete=models.CASCADE, limit_choices_to={'Active':True}) # 保留链式外键定义 course_interested= ChainedForeignKey( Course, chained_field='university_interested', chained_model_field='university', show_all=False, auto_choose=True, sort=True, limit_choices_to={"Active": True}, ) # 保留其他所有字段
第二步:正确配置django-smart-select
1. 安装依赖
确保已安装django-smart-select:
pip install django-smart-selects
2. 配置settings.py
在INSTALLED_APPS中添加应用:
INSTALLED_APPS = [ # 其他已安装应用 'smart_selects', ]
添加全局配置(复用Django自带的jQuery,Admin环境下无需额外引入):
USE_DJANGO_JQUERY = True
3. 配置urls.py
在项目根路由中添加smart-selects的路由:
from django.urls import path, include urlpatterns = [ # 其他路由 path('smart-selects/', include('smart_selects.urls')), ]
第三步:在Admin/表单中使用
Admin环境
直接注册enquiry模型即可,Admin会自动渲染动态过滤的下拉框:
from django.contrib import admin from .models import enquiry admin.site.register(enquiry)
此时在Admin添加enquiry时,选择university_interested后,course_interested会自动过滤出该大学下的有效课程。
自定义表单环境
创建ModelForm后,模板中直接渲染表单即可,smart-selects会自动注入动态过滤逻辑:
from django import forms from .models import enquiry class EnquiryForm(forms.ModelForm): class Meta: model = enquiry fields = '__all__'
模板中使用{{ form.as_p }}或手动渲染字段即可。
无JS替代方案(体验稍差)
如果不想用第三方库或JS,可采用分步提交的方式:
- 第一步表单仅让用户选择大学,提交后跳转至第二步
- 第二步根据选中的大学ID,后端过滤出对应课程,渲染最终表单
示例视图代码:
from django.shortcuts import render, redirect from .models import university, Course, enquiry from .forms import EnquiryForm def create_enquiry_step1(request): if request.method == 'POST': univ_id = request.POST.get('university') return redirect('create_enquiry_step2', univ_id=univ_id) universities = university.objects.all() return render(request, 'step1.html', {'universities': universities}) def create_enquiry_step2(request, univ_id): univ = university.objects.get(id=univ_id) courses = Course.objects.filter(university=univ, Active=True) if request.method == 'POST': form = EnquiryForm(request.POST) if form.is_valid(): form.save() return redirect('enquiry_list') else: form = EnquiryForm(initial={'university_interested': univ_id}) form.fields['course_interested'].queryset = courses return render(request, 'step2.html', {'form': form, 'univ': univ})
内容的提问来源于stack exchange,提问作者amit patel
相关产品推荐
相关产品推荐

