如何按 form.instance 属性过滤自动完成查询集?
How can i filter autocomplete queryset by form.instance attributes?
我正在尝试使用 autocomplete-light 支持过滤 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__')
自动完成JS对象需要pk值传递给调用Python自动完成对象的视图,然后你可以在choices_for_request()方法中过滤实例pk python 自动完成对象。
获取js自动完成对象的一种方法是get it from the input element itself with the jQuery plugin,即:
elements_autocomplete = $('input[name=elements-autocomplete]').yourlabsAutocomplete()
确保在 jquery-autocomplete-light 加载 JS 后调用它。
elements_autocomplete.data['panel_pk'] = {{ form.instance.pk }}
在 中,您现在可能已经明白了:
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'
你会看到自动完成脚本发出的后续请求将添加&foo=bar
到 URL 它是它,通过 self.request 使它对 choices_for_request 可用!
我正在尝试使用 autocomplete-light 支持过滤 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__')
自动完成JS对象需要pk值传递给调用Python自动完成对象的视图,然后你可以在choices_for_request()方法中过滤实例pk python 自动完成对象。
获取js自动完成对象的一种方法是get it from the input element itself with the jQuery plugin,即:
elements_autocomplete = $('input[name=elements-autocomplete]').yourlabsAutocomplete()
确保在 jquery-autocomplete-light 加载 JS 后调用它。
elements_autocomplete.data['panel_pk'] = {{ form.instance.pk }}
在
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'
你会看到自动完成脚本发出的后续请求将添加&foo=bar
到 URL 它是它,通过 self.request 使它对 choices_for_request 可用!