【问题标题】:How to use autocompleteselect widget in a modelform如何在模型表单中使用自动完成选择小部件
【发布时间】:2019-04-26 04:17:58
【问题描述】:

我知道 Django 2.0 中有一个新功能,即 ModelAdmin 中的 AutocompleteSelect 小部件。 我正在尝试在我的自定义 modelForm 中使用它,但失败了。

这样尝试过

#unit is the foreign key to the incident

class AccountForm(forms.ModelForm):
    class Meta:
        model = Invoice
        ...
        ...
        widgets = {       'incident':widgets.AutocompleteSelect(Invoice._meta.get_field('incident').remote_field, admin.site)
        }
        ...
#Invoice model

class Invoice(models.Model):
    ...
    incident = models.ForeignKey(Unit, on_delete=models.CASCADE,null=True)
    ...

希望任何人都可以帮助我。 谢谢

【问题讨论】:

  • 在你的ModelAdmin中你只需要添加autocomplete_fields = ('your_field',)
  • 不,我正在尝试在 ModelAdmin 之外执行此操作。我正在尝试以我自己的形式来做这件事
  • @Cyber​​shoe 您能找到解决方案吗?
  • 该小部件依赖于能够查询需要管理员访问权限的“自动完成”端点,因此如果该人已登录并具有“员工”和“视图”,它只会在管理员之外工作访问给定的模型。

标签: python django modelform


【解决方案1】:

AutocompleteSelect 小部件在管理站点之外无法工作。 如果您在管理站点中使用 AccountForm,您可以使用以下代码:

class AccountForm(forms.ModelForm):
    ...
    incident = forms.ModelChoiceField(
                 queryset= Unit.objects.all(),
                 widget=AutocompleteSelect(Invoice.incident.field.remote_field, admin.site),
               )
    ...
    class Meta:
        model = Invoice
        fields = [
            'incident',
            ...
        ]

@admin.register(Invoice)
class InvoiceAdmin(admin.ModelAdmin):
    form = AccountForm

【讨论】:

【解决方案2】:

AutocompleteSelect 有 2 个必需的参数,reladmin_siterel 用于提取用于从 ForeignKey 或 ManyToManyField 上的属性查询数据并与之相关的模型。因为我想在一个实际上不是 ForeignKey 的字段上使用它,所以我需要重写一些东西以使其工作:

class ClientAutocompleteSelect(AutocompleteSelect):
    def get_url(self):
        model = Client
        return reverse(self.url_name % (self.admin_site.name, model._meta.app_label, model._meta.model_name))

class ClientChoiceField(forms.ModelChoiceField):
    def __init__(self, queryset=None, widget=None, **kwargs):
        if queryset is None:
            queryset = Client.objects.all()
        if widget is None:
            widget = ClientAutocompleteSelect(None, admin.site)  # pass `None` for `rel`
        super().__init__(queryset, widget=widget, **kwargs)

    def to_python(self, value):
        return value  # just return the client_id and not a Client object

class MyAdminForm(forms.ModelForm):
    client_id=ClientChoiceField()

    ...

这要求最终用户对正在查询的模型的自动完成端点具有管理员读取权限。不过,您也许可以进行更多黑客攻击来更改 get_url,并使用您自己的端点来提供搜索结果。

【讨论】:

    【解决方案3】:

    我花了几个小时试图理解为什么我的代码(基于 @Tim 的回答)不起作用,直到我偶然发现一条关于缺少对 css/js 文件的引用的评论。

    这是一个完整的工作解决方案,可以在任何自定义表单中使用 AutocompleteSelect 小部件,供登录用户同时拥有对给定模型的“员工”和“查看”访问权限:

    from django.urls import reverse
    from django.contrib.admin.widgets import AutocompleteSelect
    from django.contrib import admin
    
    class UserAutocompleteSelect(AutocompleteSelect):
        def get_url(self):
            model = CustomUser
            return reverse(self.url_name % (self.admin_site.name, model._meta.app_label, model._meta.model_name))
    
    class UserChoiceField(forms.ModelChoiceField):
        def __init__(self, queryset=None, widget=None, **kwargs):
            if queryset is None:
                queryset = CustomUser.objects.all()
            if widget is None:
                widget = UserAutocompleteSelect(None, admin.site)  # pass `None` for `rel`
            super().__init__(queryset, widget=widget, **kwargs)
    
    class UserAutocompleteSelectForm(forms.ModelForm):
        """
        for changing user on Play objects
        using amdin module autocomplete
        """
        user = UserChoiceField(
            # queryset=CustomUser.objects.all(),
            help_text=_('Select the user to replace the current one')
        )
    
        class Meta:
            model = Play
            fields = ('user', )
    

    您可以使用相同的方法,将 CustomUserPlay 替换为您自己的模型

    如果(像我一样)这不适用于您正在使用的 html 模板,这意味着您需要将所需的 css/js 文件包含到您的模板中。这是一个简单的方法:

    如果表单在视图中声明为这样:

    form = UserAutocompleteSelectForm()
    ...
    context = {
                'form': form, 
                ...
                }
    return render(request, 'users/change_user.html', context)
    

    您应该将以下行添加到 html 模板以包含所需的 css/js 文件:

    {% block extrahead %}
    {{ block.super }}
    {{ form.media }}
    {% endblock %}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-11
      • 2021-06-30
      • 1970-01-01
      • 2011-01-13
      • 2018-11-04
      • 1970-01-01
      相关资源
      最近更新 更多