如何使用 Django 在表单中创建自动完成输入字段

how to create a autocomplete input field in a form using Django

我对 django 及其方法还很陌生。我正在尝试为表单创建一个自动完成字段。我的代码如下

forms.py

from django import forms

class LeaveForm(forms.Form):
    leave_list = (
        ('Casual Leave', 'Casual Leave'),
        ('Sick Leave', 'Sick Leave')
    )
    from_email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'style': 'width: 400px'}))
    start_date = end_date = forms.CharField(widget=forms.TextInput(attrs={'type': 'date', 'style': 'width: 175px'}))
    leave_type = forms.ChoiceField(choices=leave_list, widget=forms.Select(attrs={'style': 'width: 400px'}))
    comments = forms.CharField(required=True, widget=forms.Textarea(attrs={'style': 'width: 400px; height: 247px'}))

    def clean_from_email(self):
        data = self.cleaned_data['from_email']
        if "@testdomain.com" not in data:
            raise forms.ValidationError("Must be @testdomain.com")
        return data

我想要实现的是,当用户在 "From Email" 字段中键入单词时,我存储在外部数据库中的电子邮件列表应该出现在自动完成列表选项中。

models.py

from django.db import models


class ListOfUsers(models.Model):
    emp_number = models.CharField(db_column='Emp_Number', primary_key=True, max_length=50, unique=True)  # Field name made lowercase.
    name = models.CharField(db_column='Name', max_length=40)  # Field name made lowercase.
    supervisor = models.CharField(db_column='Supervisor', max_length=40)  # Field name made lowercase.
    email = models.CharField(db_column='Email', max_length=50, blank=False, null=False, unique=True)  # Field name made lowercase.


    class Meta:
        managed = False
        db_table = 'List of users'

知道如何做到这一点吗?

更新:

我开始摆弄 django-autocomplete-light,现在能够从自动完成中得到回复 url。看起来像这样

{"results": [{"id": "user1@mydomain.com", "text": "user1@mydomain.com"}, {"id": "user2@mydomain.com", "text": "user2@mydomain.com"}, {"id": "user3@mydomain.com", "text": "user3@mydomain.com"}]}

views.py

class EmailAutocomplete(autocomplete.Select2ListView):
    def get_list(self):
        qs = ListOfUsers.objects.using('legacy')

        if self.q:
            qs = qs.filter(email__icontains=self.q).values_list('email', flat=True)

        return qs

我仍然不知道如何让这些数据出现在字段中"from_email"

我终于使用此处找到的说明进行了自动完成搜索

https://github.com/xcash/bootstrap-autocomplete
https://bootstrap-autocomplete.readthedocs.io/en/latest/

使用起来非常简单,不需要在 settings.py 中安装任何应用程序,它适用于 bootstrap 3 和 bootstrap 4

还有很多其他可用的软件包,但这对我的需要来说简单易行。

我将解释我使用的代码

page.html

{% block script %}
    <script src="https://cdn.rawgit.com/xcash/bootstrap-autocomplete/3de7ad37/dist/latest/bootstrap-autocomplete.js"></script>
    <script>
        $('.basicAutoComplete').autoComplete(
            {minLength: 1}
        );
        $('.dropdown-menu').css({'top': 'auto', 'left': 'auto'})

    </script>
{% endblock %}
.
.
.
.
.
{% if field.name == "from_email" %}
   {% render_field field class="basicAutoComplete form-control" %}
{% else %}
   {% render_field field class="form-control" %}
{% endif %}

autoComplete 是执行操作调用的函数,minLength 指定执行提取操作之前文本的最小长度 我添加了一个额外的 CSS 来修复自动完成下拉菜单,否则它很奇怪。

Jinja 渲染不断覆盖视图中的 class 定义,因此我为其添加了一个 if 检查。

urls.py

from . import views

urlpatterns = [
    .
    .
    .
    path('email_autocomplete/', views.email_autocomplete, name='email_autocomplete')
]

将此行添加到 urls.py

forms.py

class LeaveForm(forms.Form):
    from_email = forms.EmailField(required=True, widget=forms.TextInput(
        attrs={
            'style': 'width: 400px',
            'class': 'basicAutoComplete',
            'data-url': "/domain/email_autocomplete/"
        }))

以上是forms.py中输入框的代码。 data-url 指向生成 JSON 结果的位置。

views.py

from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from .models import model
        
def email_autocomplete(request):
    if request.GET.get('q'):
        q = request.GET['q']
        data = model.objects.using('legacy').filter(email__startswith=q).values_list('email',flat=True)
        json = list(data)
        return JsonResponse(json, safe=False)
    else:
        HttpResponse("No cookies")
            

这是我最困惑的部分。 GET 请求很容易理解,但是将数据从 model.objects 转换为 JSON 格式的对象需要一段时间。诀窍是使用

values_list('columnName',flat=True)

从数据库中筛选数据,然后使用list(data)转换为列表,最后使用JsonResponse将其转换为JSON。

希望这对任何想要简单自动完成的人有所帮助

很少添加。 Abilash 的回答很好,也很清楚。 但如果它对你不起作用,也许你应该将 basicAutoComplete 激活包装到

$(document).ready(function(){
};

原因和一些解释可以在这里找到:

您可以考虑使用标准 HTML 标签 <datalist>.

获取输入元素自动完成的不同方法

考虑下面的例子。它不使用 Javascript 并且不需要在服务器代码中做任何事情。

<input list="browsers" id="browser_id" name="browser" placeholder="Starting typing the name of the browser" size="50"/>
<datalist id="browsers">
  <option>Chrome</option>
  <option>Firefox</option>
  <option>Internet Explorer</option>
  <option>Opera</option>
  <option>Safari</option>
  <option>Microsoft Edge</option>
</datalist>

关于标签的文档在这里 - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist