Django admin - автозаполнение(_field) без отношения foreignkey или manytomany

Я хотел бы узнать, существует ли функция, которая позволяет мне реализовать автозаполнение_поля без того, чтобы эта переменная была связана с другим отношением через внешний ключ.

Например, у меня есть модели Aaa, Bbb, & Ccc. Bbb & Ccc связаны с помощью внешнего ключа, а Aaa связана с двумя другими моделями через другие модели. Теперь я хочу, чтобы на стороне администратора определенное поле Ccc, которое состоит из поля в Aaa, автозаполнялось значениями из Aaa (или хотя бы функцией предложения, чтобы минимизировать ошибки). Однако Ccc и Aaa не связаны напрямую; поэтому я считаю недействительным просто присвоить этому элементу внешний ключ. Есть предложения, как решить эту проблему?

Как вы можете понять из моего вопроса, я довольно новичок в django и был бы очень благодарен за некоторую помощь здесь.

Вы можете подклассифицировать их и сделать некоторые "обезьяньи" исправления для повторного использования логики автозаполнения Django:

  1. django.contrib.admin.widgets.AutocompleteSelect
  2. django.contrib.admin.ModelAdmin
  3. django.contrib.admin.views.autocomplete.AutocompleteJsonView
class MyAutocompleteSelectWidget(widgets.AutocompleteSelect):
    url_name = 'my_autocomplete'

    def get_url(self):
        return reverse(self.url_name)

    def optgroups(self, name, value, attr=None):
        return None
class MyAutocompleteModelAdmin(admin.ModelAdmin):
    my_autocomplete_fields = {}

    def __init__(self, model, admin_site):
        super().__init__(model, admin_site)
        # Patch remote_field for AutocompleteJsonView.process_request
        for field_name, deferred_remote_field in self.my_autocomplete_fields.items():
            remote_field = deferred_remote_field.field
            self.model._meta.get_field(field_name).remote_field = SimpleNamespace(field_name=remote_field.attname, model=remote_field.model)

    def formfield_for_dbfield(self, db_field, request, **kwargs):
        if 'widget' not in kwargs:
            if db_field.name in self.my_autocomplete_fields:
                kwargs['widget'] = MyAutocompleteSelectWidget(db_field, self.admin_site)
        return super().formfield_for_dbfield(db_field, request, **kwargs)

    def to_field_allowed(self, request, to_field):
        # Allow search fields that are not referenced by foreign key fields
        if to_field in self.search_fields:
            return True
        return super().to_field_allowed(request, to_field)
class MyAutocompleteJsonView(autocomplete.AutocompleteJsonView):

    def get_queryset(self):
        # Patch get_limit_choices_to for non-foreign key field
        self.source_field.get_limit_choices_to = lambda: {}
        return super().get_queryset()

    def process_request(self, request):
        term, model_admin, source_field, to_field_name = super().process_request(request)
        # Store to_field_name for use in get_context_data
        self.to_field_name = to_field_name
        return term, model_admin, source_field, to_field_name

    def get_context_data(self, *, object_list=None, **kwargs):
        context_data = super().get_context_data(object_list=object_list, **kwargs)
        # Patch __str__ to use to_field_name for `str(obj)` in AutocompleteJsonView.get
        for obj in context_data['object_list']:
            obj_type = type(obj)
            new_obj_type = type(obj_type.__name__, (obj_type,), {'__str__': lambda _self: getattr(_self, self.to_field_name), '__module__': obj_type.__module__})
            obj.__class__ = new_obj_type
        return context_data

Использование:

@admin.register(Aaa)
class AaaAdmin(MyAutocompleteModelAdmin):
    search_fields = ('a_field',)


@admin.register(Ccc)
class CccAdmin(MyAutocompleteModelAdmin):
    my_autocomplete_fields = {
        'a_specific_field': Aaa.a_field,
    }
path('my_autocomplete', MyAutocompleteJsonView.as_view(admin_site=admin.site), name='my_autocomplete')
Вернуться на верх