【问题标题】:How can i filter autocomplete queryset by form.instance attributes?如何按 form.instance 属性过滤自动完成查询集?
【发布时间】:2016-01-11 10:46:42
【问题描述】:

我正在尝试使用自动完成光支持过滤 M2M 查询集。 我可以让过滤器与内置的 ModelForm 一起工作。这是代码的简化版本,无需自动完成即可完美运行:

models.py:

class FEmodel(models.Model):
    name = models.Charfield(max_length=200)

class Workspace(models.Model):
    name = models.Charfield(max_length=200)
    fem = models.ForeignKey(FEmodel)

class Element(models.Model):
    EID = models.PositiveIntegerField()
    fem = models.ForeignKey(FEmodel)

class Panel(models.Model):
    workspace = models.ForeignKey(Workspace)
    elements = models.ManyToManyField(Element)

forms.py:

class PanelForm(forms.ModelForm):
    def __init__(self,*args,**kwargs):
        super(PanelForm,self).__init__(*args,**kwargs)
        ws = self.instance.workspace
        self.fields['elements'].queryset = Element.objects.filter(fem=ws.fem)
    class Meta:
        model = Panel
        fields = ('__all__')

views.py:

@login_required(login_url='/login/')
def panel_edit(request, pk, id=None):
    workspace = get_object_or_404(Workspace, pk=pk)
    if id:
        panel = get_object_or_404(Panel, pk=id)
    else:
        panel = Panel(workspace = workspace)
    if request.method == 'POST':
        form = PanelForm(request.POST, instance=panel)    
        if form.is_valid():
            panel = form.save(commit=True)        
            return panels(request, pk)
        else:
            print form.errors
    else:
        form = PanelForm(instance=panel)

    return render(request, 'structures/Panel/panel_edit.html', {'form': form, 'panel': panel, 'workspace': workspace})

urls.py:

...
url(r'^workspace/(?P<pk>[0-9]+)/panel/new/$', views.panel_edit, name='panel_edit'),
...

panel_edit.html:

...
<form method="POST" class="form-horizontal">
    {% csrf_token %}
    {% bootstrap_form form %}
    {% buttons %}
        <button type="submit"> Save</button>
    {% endbuttons %}
</form>
....

这是我无法使用的自动完成版本:

autocomplete_light_registry.py

class ElementAutocomplete(acl.AutocompleteModelBase):
    search_fields = ['EID']
acl.register(Element, ElementAutocomplete)

forms.py:

import autocomplete_light.shortcuts as acl

class PanelForm(acl.ModelForm):
    def __init__(self,*args,**kwargs):
        super(PanelForm,self).__init__(*args,**kwargs)
        ws = self.instance.workspace
        self.fields['elements'].queryset = Element.objects.filter(fem=ws.fem)
    class Meta:
        model = Panel
        fields = ('__all__')

此版本不会引发错误,但不提供按 form.instance.ws.fem 属性过滤的元素选择。相反,它提供了所有 Element 对象。

我做错了什么?

编辑 1:

  • forms.py 中的 super(Panel,self) 被更正为 super(PanelForm,self)
  • 缩进错别字已更正

编辑 2:添加了所需的 url、视图和模板部分

编辑 3: 根据@jpic 的回答,这里是解决方案:

添加到 panel_edit.html:

{% block bootstrap3_extra_head %}
{{ block.super }}

<script type="text/javascript">
    $( document ).ready(function() {
        elements_autocomplete = $('input[name=elements-autocomplete]').yourlabsAutocomplete()
        elements_autocomplete.data['ws_pk'] = {{ form.instance.workspace.pk }}
    });

</script>

{% endblock %}

autocomplete_light_registry.py:

import autocomplete_light as acl

class ElementAutocomplete(acl.AutocompleteModelBase):
    search_fields = ['EID']
    model = Element

    def choices_for_request(self):
        ws = Workspace.objects.get(pk=self.request.GET.get('ws_pk', None))
        self.choices = self.choices.filter(fem=ws.fem)
        return super(ElementAutocomplete, self).choices_for_request()

acl.register(ElementAutocomplete)

forms.py:

class PanelForm(acl.ModelForm):

    class Meta:
        model = Panel
        fields = ('__all__')

【问题讨论】:

  • 浏览量和网址怎么样?
  • @jpic 添加。顺便说一句,通过 javascript 在客户端操作选择不是我的选择,因为它会导致性能问题。

标签: python django django-autocomplete-light


【解决方案1】:

自动完成JS对象需要pk值传递给调用Python自动完成对象的视图,然后你可以在python自动完成对象的choices_for_request()方法中过滤实例pk。

获取js自动补全对象的一种方法是get it from the input element itself with the jQuery plugin,即:

elements_autocomplete = $('input[name=elements-autocomplete]').yourlabsAutocomplete()

确保在 jquery-autocomplete-light JS 加载之后调用它。

那么,add the fk to its data

elements_autocomplete.data['panel_pk'] = {{ form.instance.pk }}

choices_for_request(),你现在可能想通了:

def choices_for_request(self):
    choices = super(ElementAutocomplete, self).choices_for_request()

    panel_pk = request.GET.get('panel_pk', None)
    if panel_pk and panel_pk.isdigit():
        choices = choices.filter(panel__pk=panel_pk)

    return choices

实际上,这很容易测试,在浏览器中打开 JS 控制台并运行:$('input[name=elements-autocomplete]').yourlabsAutocomplete().data['foo'] = 'bar',您会看到自动完成脚本发出的后续请求会将 &amp;foo=bar 添加到它的 URL 中,使得通过 self.request 对choices_for_request 可用!

【讨论】:

  • 就是这样,谢谢!你的建议完成了工作。我不得不稍微调整一下choices_for_request() 方法。我将整个工作集报告为可能的新人的新编辑。
猜你喜欢
  • 1970-01-01
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-07
  • 1970-01-01
  • 2018-02-14
相关资源
最近更新 更多