Django Admin中基于远程JSON API实现CharField自动补全
实现Django 2.0.1 Admin普通CharField远程API自动补全(基于Select2)
既然你之前已经用过Select2处理过ForeignKey的自动补全,那咱们直接基于这个熟悉的工具扩展就行,上手快还能保持体验一致。下面是一步步的具体实现方案:
1. 编写远程API视图,返回自定义结构JSON
首先得搭个后端接口,用来返回你需要的补全选项。这里我假设你要返回的自定义结构是{"items": [{"code": "xxx", "name": "yyy"}, ...]},你可以根据自己的需求调整结构和数据来源:
# 在你的app的views.py中 from django.http import JsonResponse from django.views.decorators.http import require_GET from django.contrib.admin.views.decorators import staff_member_required # 仅限Admin用户访问 @require_GET @staff_member_required def char_autocomplete(request): # 获取Select2默认传入的搜索关键词参数q query = request.GET.get('q', '') # 这里替换成你的实际逻辑:调用外部API/生成自定义数据 mock_items = [ {"code": "A001", "name": "Apple"}, {"code": "B002", "name": "Banana"}, {"code": "C003", "name": "Cherry"} ] # 根据关键词过滤数据 filtered_items = [item for item in mock_items if query.lower() in item['name'].lower()] # 返回自定义结构的JSON响应 return JsonResponse({"items": filtered_items})
接着在项目的urls.py里给这个视图配置路由:
from django.urls import path from your_app.views import char_autocomplete urlpatterns = [ # ... 其他原有路由 path('admin/char-autocomplete/', char_autocomplete, name='char_autocomplete'), ]
2. 自定义Admin专用Widget
我们需要给目标CharField创建一个带Select2自动补全能力的Widget,继承Django内置的Admin文本输入组件:
# 可以放在app的admin.py里,或者单独建widgets.py文件 from django.contrib.admin.widgets import AdminTextInputWidget class RemoteAutocompleteWidget(AdminTextInputWidget): # 声明需要加载的Select2静态资源 class Media: css = { 'all': ('//cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css',) } js = ( '//cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js', '//cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js', ) def render(self, name, value, attrs=None, renderer=None): # 给输入框添加专属class,方便后面初始化Select2 if attrs is None: attrs = {} attrs['class'] = f"{attrs.get('class', '')} remote-autocomplete".strip() # 调用父类方法生成基础输入框 return super().render(name, value, attrs, renderer)
3. 在ModelAdmin中绑定Widget到目标字段
找到你要修改的ModelAdmin,把自定义Widget绑定到指定的CharField上。这里推荐用自定义Form的方式,能精准控制单个字段:
# 在app的admin.py里 from django.contrib import admin from django import forms from .models import YourModel from .widgets import RemoteAutocompleteWidget @admin.register(YourModel) class YourModelAdmin(admin.ModelAdmin): # 自定义表单,指定字段的Widget class YourCustomForm(forms.ModelForm): class Meta: model = YourModel fields = '__all__' widgets = { 'target_char_field': RemoteAutocompleteWidget(), # 替换成你的实际字段名 } form = YourCustomForm
4. 编写Select2初始化脚本
最后需要在Admin的表单页面里添加JS,初始化Select2并配置远程数据源。我们通过重写ModelAdmin的表单模板来实现:
首先在你的app下创建模板文件templates/admin/your_app/your_model/change_form.html(路径要对应你的app和model名称):
{% extends "admin/change_form.html" %} {% block extrahead %} {{ block.super }} <script type="text/javascript"> (function($) { $(document).ready(function() { // 找到带专属class的输入框,初始化Select2 $('.remote-autocomplete').select2({ ajax: { url: "{% url 'char_autocomplete' %}", // 对应之前配置的路由名称 dataType: 'json', delay: 250, // 输入延迟250ms再请求,减少无效请求 data: function(params) { return { q: params.term, // 传递搜索关键词给后端 page: params.page || 1 }; }, processResults: function(data, params) { // 把后端返回的自定义JSON转换成Select2需要的格式 // Select2要求返回结构:{results: [{id: 'xxx', text: 'yyy'}, ...], pagination: {more: 布尔值}} var results = data.items.map(function(item) { return { id: item.code, // 选中后存入CharField的值 text: item.name // 下拉列表显示的文本 }; }); return { results: results, pagination: { more: false // 如果需要分页,这里可以判断是否还有更多数据 } }; }, cache: true }, minimumInputLength: 1, // 输入至少1个字符才触发搜索 placeholder: "输入关键词搜索...", allowClear: true // 允许清空选中值 }); }); })(jQuery); </script> {% endblock %}
然后在ModelAdmin里指定这个自定义模板:
class YourModelAdmin(admin.ModelAdmin): # ... 其他配置 change_form_template = 'admin/your_app/your_model/change_form.html'
一些注意点
- 我选的Select2 4.0.13和jQuery 3.6.0版本是和Django 2.0.1兼容的,别随便换高版本避免兼容性问题。
- 如果你的自定义JSON结构和示例不一样,只需要修改
processResults里的映射逻辑,把你的数据字段对应到Select2需要的id和text即可。 - 测试前记得清浏览器缓存,Admin的静态资源有时候会缓存旧代码。
这样一套配置下来,你的普通CharField就能从远程API获取自动补全选项了,而且和你之前用的Select2体验完全统一。
内容的提问来源于stack exchange,提问作者Lorenzo Morandini
相关产品推荐
相关产品推荐

