字段显示正常的原因select
小部件的特点是,当您定义自定义字段时,您不会将小部件设置为AutocompleteSelect
.
In the ModelAdmin
您指定的类autocomplete_fields
,导入你的CustomDisplay
and AutocompleteSelect
并添加以下方法:
from django.contrib.admin.widgets import AutocompleteSelect
class YourModelAdmin(admin.ModelAdmin):
autocomplete_fields = ['something']
...
def formfield_for_foreignkey(self, db_field, request, **kwargs):
db = kwargs.get('using')
if db_field.name == 'something':
return CustomDisplay(queryset=Something.object.all(), widget=AutocompleteSelect(db_field.remote_field, self.admin_site, using=db))
return super().formfield_for_foreignkey(db_field, request, **kwargs)
这只会在您查看现有实例时显示自定义文本。当您查看自动完成下拉列表并选择一个条目时,不会生成标签label_from_instance()
,但是从简单的str()
里面打电话AutocompleteJsonView
.
因此,假设您只想更改自动完成小部件中的标签(要全面更改标签,您显然只需更改模型__str()__
方法),您还需要在中创建一个自定义类admin.py
这修改了get()
中的方法AutocompleteJsonView
:
from django.contrib.admin.options import AutocompleteJsonView
from django.http import Http404, JsonResponse
class CustomAutocompleteJsonView(AutocompleteJsonView):
def get(self, request, *args, **kwargs):
if not self.model_admin.get_search_fields(request):
raise Http404(
'%s must have search_fields for the autocomplete_view.' %
type(self.model_admin).__name__
)
if not self.has_perm(request):
return JsonResponse({'error': '403 Forbidden'}, status=403)
self.term = request.GET.get('term', '')
self.paginator_class = self.model_admin.paginator
self.object_list = self.get_queryset()
context = self.get_context_data()
# Replace this with the code below.
#
# return JsonResponse({
# 'results': [
# {'id': str(obj.pk), 'text': str(obj)}
# for obj in context['object_list']
# ],
# 'pagination': {'more': context['page_obj'].has_next()},
# })
return JsonResponse({
'results': [
{'id': str(obj.pk), 'text': 'Some custom text: {}'.format(obj.name)}
for obj in context['object_list']
],
'pagination': {'more': context['page_obj'].has_next()},
})
现在设置autocomplete_view
on the ModelAdmin
自动完成功能正在显示结果的类(不是ModelAdmin
您指定 autocomplete_fields 的类):
def autocomplete_view(self, request):
return CustomAutocompleteJsonView.as_view(model_admin=self)(request)
所以如果你有一个ModelAdmin
类称为YourModelAdmin
with autocomplete_fields = ['something']
,你会设置autocomplete_view
对于相应的ModelAdmin
为你的班级Something
model.
Django 4.2 更新:
from django.contrib.admin.sites import AdminSite
from django.contrib.admin.widgets import AutocompleteSelect
from django.contrib.admin.views.autocomplete import AutocompleteJsonView
from django.core.exceptions import PermissionDenied
class CustomAdminSite(AdminSite):
# This will change the view for all autocompletes.
# You can handle specific cases within the autocomplete get() method.
def autocomplete_view(self, request):
return CustomAutocompleteJsonView.as_view(admin_site=self)(request)
admin_site = CustomAdminSite()
class CustomAutocompleteJsonView(AutocompleteJsonView):
def get(self, request, *args, **kwargs):
(
self.term,
self.model_admin,
self.source_field,
to_field_name,
) = self.process_request(request)
if not self.has_perm(request):
raise PermissionDenied
self.object_list = self.get_queryset()
context = self.get_context_data()
if type(self.model_admin) == SomethingModelAdmin:
return JsonResponse(
{
"results": [
{'id': str(obj.pk), 'text': 'Some custom text: {}'.format(obj.name)}
for obj in context['object_list']
],
"pagination": {"more": context["page_obj"].has_next()},
}
)
else:
return super().get(request, *args, **kwargs)
class YourModelAdmin(admin.ModelAdmin):
autocomplete_fields = ['something']
...
def formfield_for_foreignkey(self, db_field, request, **kwargs):
db = kwargs.get('using')
if db_field.name == 'something':
return CustomDisplay(queryset=Something.objects.all(),
widget=AutocompleteSelect(db_field,
self.admin_site,
using=db))
return super().formfield_for_foreignkey(db_field, request, **kwargs)