Поле обратного внешнего ключа автозаполнения 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

Вернуться на верх