Поле обратного внешнего ключа автозаполнения Django
У меня есть две модели
models.py
class Group(models.Model):
name = models.CharField()
class Book(models.Model):
name = models.CharField()
group = models.ForeignKey(Group, on_delete=models.SET_NULL, related_name='books', related_query_name="book", null=True, blank=True)
Мне нужно в админ-панели добавить в группу форму множественного выбора книг.
Я успешно решил эту проблему, используя приведенный ниже код.
admin.py
from .models import Group, Book
from django.forms import ModelForm, ModelMultipleChoiceField
from django.contrib.admin import widgets
class Group_ModelForm(ModelForm):
books = ModelMultipleChoiceField(queryset=Book.objects.all(), widget=widgets.FilteredSelectMultiple('Books', False), required=True, label='Books')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'instance' in kwargs and kwargs['instance'] is not None:
self.fields['books'].initial = kwargs['books'].books.all()
@admin.register(Group)
class Group_ModelAdmin(admin.ModelAdmin):
list_display = ['name']
list_display_links = ['name']
fields = ['books', 'name']
form = Group_ModelForm
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
if change:
Book.objects.filter(group=obj).update(group=None)
form.cleaned_data['books'].update(group=obj)
Но когда количество книг превысило 100 000, загрузка групповой формы заняла много времени, поскольку FilteredSelectMultiple загружает все 100 000 объектов при запуске.
Я пытаюсь заменить FilteredSelectMultiple widget на автозаполнение Select Multiple widget, но автозаполнение Selectmultiple не работает без поля "многие ко многим" в групповой модели. Я попытался переопределить класс AutocompleteMixin для создания пользовательского виджета AutocompleteSelectMultiple, но у меня ничего не получилось: для виджета AutocompleteSelectMultiple по-прежнему требовалось поле "многие ко многим" в групповой модели.
Как сделать autocompleteselectwidget для пользовательских полевых книг в форме группы?
P.S. В форме группы мне нужно выбрать существующие книги. Мне не нужна онлайн-форма для создания новых книг.
Я использую Django 4.2
Я успешно справился со своей задачей. Вот что вам нужно сделать:
В проекте urls.py
from django.contrib.admin.views.autocomplete import AutocompleteJsonView
from django.apps import apps
from django.core.exceptions import PermissionDenied
from django.http import Http404
class AutocompleteJsonView_for_custom_field(AutocompleteJsonView):
def process_request(self, request):
term = request.GET.get("term", "")
try:
app_label = request.GET["app_label"]
model_name = request.GET["model_name"]
except KeyError as e:
raise PermissionDenied from e
# Retrieve objects from parameters.
try:
remote_model = apps.get_model(app_label, model_name)
except LookupError as e:
raise PermissionDenied from e
try:
model_admin = self.admin_site._registry[remote_model]
except KeyError as e:
raise PermissionDenied from e
# Validate suitability of objects.
if not model_admin.get_search_fields(request):
raise Http404(
"%s must have search_fields for the autocomplete_view."
% type(model_admin).__qualname__
)
to_field_name = remote_model._meta.pk.attname
if not model_admin.to_field_allowed(request, to_field_name):
raise PermissionDenied
return term, model_admin, None, to_field_name
def get_queryset(self):
"""Return queryset based on ModelAdmin.get_search_results()."""
qs = self.model_admin.get_queryset(self.request)
# qs = qs.complex_filter(self.source_field.get_limit_choices_to())
qs, search_use_distinct = self.model_admin.get_search_results(
self.request, qs, self.term
)
if search_use_distinct:
qs = qs.distinct()
return qs
urlpatterns = [
...
path('admin_ajax/autocomplete_for_custom_field', AutocompleteJsonView_for_custom_field.as_view(admin_site=admin.site), name='autocomplete_for_custom_field'),
]
В admin.py