Django,如何在自定义表单中使用管理自动完成字段

run*_*ace 9 django

在 Django 管理界面中,您可以将字段设置为自动完成字段,例如:

autocomplete_fields = ('countries', )
Run Code Online (Sandbox Code Playgroud)

这对管理页面很有用,如何在自定义视图/表单中使用自动完成字段?我的研究指向 django-autocomplete-light,但是当 Django 已经具有内置功能时,安装 3rd 方包似乎并不理想。

Kou*_*und 12

实际上,可以使用管理员的 select2。您只需要使用AutocompleteSelect小部件。AutocompleteSelect 小部件需要一个关系和一个管理站点。

如果您的模型A有一个 ForeignKey 字段指向B您想要使用 AutocompleteSelect 的模型,您只需使用(如cuto所建议的那样)。

from django.contrib.admin.widgets import AutocompleteSelect
from myapp.model import ModelA, ModelB
from django.contrib import admin


class MyForm(form.Form):
    model_b = forms.ModelChoiceField(
        queryset=ModelB.objects.all(),
        widget=AutocompleteSelect(ModelA._meta.get_field('model_b').remote_field, admin.AdminSite)
    )

Run Code Online (Sandbox Code Playgroud)

因为我没有关系,所以我使用了一个FakeRelation类,因为get_url(self)函数只使用模型属性。AutocompleteSelect 小部件的使用与 autocomplete_fields 小部件的使用绑定到相同的条件。

from django.contrib.admin.widgets import AutocompleteSelect
from django.contrib import admin
from django import forms
from myapp.models import countries

class FakeRelation:
    def __init__(self, model):
        self.model = model


class CustomAutocompleteSelect (AutocompleteSelect):
    def __init__(self, model, admin_site, attrs=None, choices=(), using=None):
        rel = FakeRelation(model)
        super().__init__(rel, admin_site, attrs=attrs, choices=choices, using=using)

class PreventionPlanForm(form.Form):
    DateFrom = forms.DateField(label="From")
    DateTo = forms.DateField(label="To")
    PE1_Name = forms.ModelChoiceField(
        queryset=countries.objects.all(),
        widget=CustomAutocompleteSelect(countries, admin.AdminSite)
    )
Run Code Online (Sandbox Code Playgroud)

正如jenniwren指出的:确保在您的模板中加载正确的 Javascripts/CSS 文件(路径可能会在不同的 Django 版本中发生变化):

  • 管理员/CSS/供应商/select2/select2.css
  • admin/js/vendor/select2/select2.full.js
  • 管理/css/autocomplete.css
  • 管理员/js/autocomplete.js

  • 这(第一个代码)对我有用,但我必须将 admin.AdminSite 更改为 admin.site (7认同)
  • 感谢这个解决方案!尽管现在看起来很明显,但我还是花了一点时间才弄清楚:确保将适当的 css/js 文件添加到非管理页面的模板中。对于 Django 2.2,这包括 `admin/css/vendor/select2/select2.css`、`admin/js/vendor/select2/select2.full.js`、`admin/css/autocomplete.css`、`admin/js/自动完成.js`。 (3认同)
  • 无需自己添加静态文件,只需在 html 模板中添加 `{{form.media}}` 即可自动导入所需的文件。 (2认同)

小智 6

之前提出的 FakeRelation 解决方案不再适用于 Django 2.2,它需要 AutocompleteSelect 构造函数的字段实例。
我的项目中有一个合适的字段,因此我可以使用它,但必须传递字段实例而不是关系。以下是自定义 AutocompleteSelect 的代码,其中还添加了将特定占位符传递给 Select2 的选项:

class CustomAutocompleteSelect(AutocompleteSelect):
    def __init__(self, field, prompt="", admin_site=None, attrs=None, choices=(), using=None):
        self.prompt = prompt
        super().__init__(field, admin_site, attrs=attrs, choices=choices, using=using)

    def build_attrs(self, base_attrs, extra_attrs=None):
        attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs)
        attrs.update({
            'data-ajax--delay': 250,
            'data-placeholder': self.prompt,
            'style': 'width: 30em;'
        })
        return attrs


class AddLittermateForm(forms.Form):
    new_littermate = forms.ModelChoiceField(
        queryset=Dog.objects.all(),
        widget=CustomAutocompleteSelect(LitterDog._meta.get_field(
            'dog'), "Search for a littermate here", admin.site)
    )
Run Code Online (Sandbox Code Playgroud)

如果没有一个具有合适关系的模型,他们将不得不声明一个不受管理的模型:

...
class Meta:
    managed = False
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案在 Django 4.1 中对我有用你可能想从 @skratt 的答案中添加到模板代码中: `{% block extrahead %} {{ block.super }} {{ form.media }} {% endblock %} ` (2认同)