管理操作的中间页面上的动态下拉列表
Dynamic dropdown on intermediate page for admin action
我有一个模型 Jar
,它有一个 crate
属性 -- ForeignKey
到 Crate
模型。 Crate
模型有一个 capacity
属性(它可以容纳的罐子数量)和一个 jars
属性(它当前容纳的罐子数量)是这一行: return self.jar_set.filter(is_active=True).count()
.
我有一个管理操作,可以将多个 jar 移到一个新的箱子中。它使用中间页面 select 目标板条箱。现在所有板条箱都列在下拉列表中,但我想将列出的板条箱限制为只有那些有空间容纳罐子数量 selected 的板条箱。怎么样?
这是来自 admin.py
的管理员操作:
class MoveMultipleJarsForm(forms.Form):
# This needs to somehow be restricted to those crates that have room
dest = forms.ModelChoiceField(queryset=Crate.objects.all().order_by('number'))
def move_multiple_jars(self, request, queryset):
form = None
if 'apply' in request.POST:
form = self.MoveMultipleJarsForm(request.POST)
if form.is_valid():
dest = form.cleaned_data['dest']
count = 0
for jar in queryset:
jar.crate = dest
jar.save()
count += 1
plural = ''
if count != 1:
plural = 's'
self.message_user(request, "Successfully moved %d jar%s to %s" % (count, plural, dest))
return HttpResponseRedirect(request.get_full_path())
if not form:
form = self.MoveMultipleJarsForm()
return render(request, 'admin/move_multiple_jars.djhtml', {
'jars': queryset,
'move_multiple_jars_form': form,
})
move_multiple_jars.short_description = "Move multiple jars to new crate"
借助 Python Developers Slack 服务器上的 laidibug,我想出了一个解决方案。
class MoveMultipleJarsForm(forms.Form):
dest = forms.ModelChoiceField(Crate.objects.none())
def __init__(self, *args, **kwargs):
count = kwargs.pop('count')
super().__init__(*args, **kwargs)
self.fields['dest'].queryset = Crate.objects.annotate(room=F('capacity')-Sum(Case(When(jar__is_active=True, then=1), default=0), output_field=IntegerField())).filter(room__gte=count).order_by('number')
def move_multiple_jars(self, request, queryset):
form = None
if 'apply' in request.POST:
form = self.MoveMultipleJarsForm(request.POST)
if form.is_valid():
dest = form.cleaned_data['dest']
count = 0
for jar in queryset:
jar.crate = dest
jar.save()
count += 1
plural = ''
if count != 1:
plural = 's'
self.message_user(request, "Successfully moved %d jar%s to %s" % (count, plural, dest))
return HttpResponseRedirect(request.get_full_path())
if not form:
form = self.MoveMultipleJarsForm(count=queryset.count())
return render(request, 'admin/move_multiple_jars.djhtml', {
'jars': queryset,
'move_multiple_jars_form': form,
})
move_multiple_jars.short_description = "Move multiple jars to new crate"
解决方案的第一步是修改表单 class 以将查询集中的 jar 数量作为初始化值传递,然后可以更改目标 crate 列表。我有一个 Subquery
和 OuterRef
的 90% 解决方案,但它无法处理没有活动罐子的板条箱。我在这个问题中接受了公认的答案: 奇怪的是,我的 90% 解决方案与他们针对 Django 1.11 的解决方案类似,但我猜他们并不担心没有参与者的情况。我在那个问题中给出了另一个被接受的答案,因为如果我最初看到它,我可能不必 post 这个问题。
我有一个模型 Jar
,它有一个 crate
属性 -- ForeignKey
到 Crate
模型。 Crate
模型有一个 capacity
属性(它可以容纳的罐子数量)和一个 jars
属性(它当前容纳的罐子数量)是这一行: return self.jar_set.filter(is_active=True).count()
.
我有一个管理操作,可以将多个 jar 移到一个新的箱子中。它使用中间页面 select 目标板条箱。现在所有板条箱都列在下拉列表中,但我想将列出的板条箱限制为只有那些有空间容纳罐子数量 selected 的板条箱。怎么样?
这是来自 admin.py
的管理员操作:
class MoveMultipleJarsForm(forms.Form):
# This needs to somehow be restricted to those crates that have room
dest = forms.ModelChoiceField(queryset=Crate.objects.all().order_by('number'))
def move_multiple_jars(self, request, queryset):
form = None
if 'apply' in request.POST:
form = self.MoveMultipleJarsForm(request.POST)
if form.is_valid():
dest = form.cleaned_data['dest']
count = 0
for jar in queryset:
jar.crate = dest
jar.save()
count += 1
plural = ''
if count != 1:
plural = 's'
self.message_user(request, "Successfully moved %d jar%s to %s" % (count, plural, dest))
return HttpResponseRedirect(request.get_full_path())
if not form:
form = self.MoveMultipleJarsForm()
return render(request, 'admin/move_multiple_jars.djhtml', {
'jars': queryset,
'move_multiple_jars_form': form,
})
move_multiple_jars.short_description = "Move multiple jars to new crate"
借助 Python Developers Slack 服务器上的 laidibug,我想出了一个解决方案。
class MoveMultipleJarsForm(forms.Form):
dest = forms.ModelChoiceField(Crate.objects.none())
def __init__(self, *args, **kwargs):
count = kwargs.pop('count')
super().__init__(*args, **kwargs)
self.fields['dest'].queryset = Crate.objects.annotate(room=F('capacity')-Sum(Case(When(jar__is_active=True, then=1), default=0), output_field=IntegerField())).filter(room__gte=count).order_by('number')
def move_multiple_jars(self, request, queryset):
form = None
if 'apply' in request.POST:
form = self.MoveMultipleJarsForm(request.POST)
if form.is_valid():
dest = form.cleaned_data['dest']
count = 0
for jar in queryset:
jar.crate = dest
jar.save()
count += 1
plural = ''
if count != 1:
plural = 's'
self.message_user(request, "Successfully moved %d jar%s to %s" % (count, plural, dest))
return HttpResponseRedirect(request.get_full_path())
if not form:
form = self.MoveMultipleJarsForm(count=queryset.count())
return render(request, 'admin/move_multiple_jars.djhtml', {
'jars': queryset,
'move_multiple_jars_form': form,
})
move_multiple_jars.short_description = "Move multiple jars to new crate"
解决方案的第一步是修改表单 class 以将查询集中的 jar 数量作为初始化值传递,然后可以更改目标 crate 列表。我有一个 Subquery
和 OuterRef
的 90% 解决方案,但它无法处理没有活动罐子的板条箱。我在这个问题中接受了公认的答案: