根据对先前表单的选择,在表单工具向导中限制 Django 表单的 ManyToManyField 查询集
Limiting a Django form's ManyToManyField queryset in a formtools wizard based on selection on previous form
我正在使用 django-formtools 中的 SessionWizardView
构建一个双窗体向导。我面临的挑战是我需要引用第一种形式的输入来限制第二种形式的可用查询集。
为了让它更有趣,我使用脆皮形式进行布局,查询集需要通过相关项目上的方法进行限制。
这是我所处位置的(大大简化的)要点:
型号
class Product(models.Model):
# pk, name, etc....
catalogitem = ForeignKey("myapp.CatalogItem")
colors = ManyToManyField("myapp.Colors")
class Colors(models.Model):
# pk, name, etc....
class CatalogItem(models.Model):
# Colors are stored within CatalogVariants, which I've left
# as a blackbox in this example, since they are retrieved as
# a queryset on this model with this method:
# pk, name, etc....
def get_colors(self):
# Returns a queryset of color objects.
观看次数
ProductFormWizard(SessionWizardView):
form_list = [
productFormWizard_Step1,
productFormWizard_Step2,
]
def get_context_data(self, **kwargs):
# ...
pass
def get_form_initial(self, step):
initial = {}
# ...
return self.initial_dict.get(step, initial)
def process_step(self, form):
if self.steps.step1 == 1:
pass
return self.get_form_step_data(form)
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
表格
productFormWizard_Step1(forms.ModelForm):
# Defines a form where the user selects a CatalogProduct.
model = Product
productFormWizard_Step2(forms.ModelForm):
"""
Defines a form where the user chooses colors based on
the CatalogProduct they selected in the previous step.
"""
model = Product
根据 Google 的研究和一些 SO 问题(none 其中 =direct= 相关),我假设我需要将 .queryset
属性 设置为colors
字段,但我不确定在哪里做。两个想法:
- 我猜它会以某种方式进入
.get_form_initial()
,但我不知道实现它的最佳方法。
- 或者,适当的代码可能会以某种方式进入
productFormWizard.get_context_data()
方法。
在 .get_form_initial() 中,我可以这样做:
if step == '1':
itemID = self.storage.get_step_data('0').data.get('0-pfProduct', "")
if itemID:
obj = CatalogItem.objects.get(id=itemID)
initial['colors'] = obj.get_get_colors()
但是,这只是选择可用的相关项目...它不会限制列表。
附加信息
Python == 3.5.3
Django == 1.10.6
django-crispy-forms == 1.6.1
django-formtools == 2.0
解决方案是覆盖视图上的 .get_form()
方法:
def get_form(self, step=None, data=None, files=None):
form = super(bzProductFormWizard, self).get_form(step, data, files)
if step == '1':
past_data = self.get_cleaned_data_for_step('0')
product = past_data['product']
form.fields['colors'].queryset = ... #CUSTOM QUERYSET
return form
我正在使用 django-formtools 中的 SessionWizardView
构建一个双窗体向导。我面临的挑战是我需要引用第一种形式的输入来限制第二种形式的可用查询集。
为了让它更有趣,我使用脆皮形式进行布局,查询集需要通过相关项目上的方法进行限制。
这是我所处位置的(大大简化的)要点:
型号
class Product(models.Model):
# pk, name, etc....
catalogitem = ForeignKey("myapp.CatalogItem")
colors = ManyToManyField("myapp.Colors")
class Colors(models.Model):
# pk, name, etc....
class CatalogItem(models.Model):
# Colors are stored within CatalogVariants, which I've left
# as a blackbox in this example, since they are retrieved as
# a queryset on this model with this method:
# pk, name, etc....
def get_colors(self):
# Returns a queryset of color objects.
观看次数
ProductFormWizard(SessionWizardView):
form_list = [
productFormWizard_Step1,
productFormWizard_Step2,
]
def get_context_data(self, **kwargs):
# ...
pass
def get_form_initial(self, step):
initial = {}
# ...
return self.initial_dict.get(step, initial)
def process_step(self, form):
if self.steps.step1 == 1:
pass
return self.get_form_step_data(form)
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
表格
productFormWizard_Step1(forms.ModelForm):
# Defines a form where the user selects a CatalogProduct.
model = Product
productFormWizard_Step2(forms.ModelForm):
"""
Defines a form where the user chooses colors based on
the CatalogProduct they selected in the previous step.
"""
model = Product
根据 Google 的研究和一些 SO 问题(none 其中 =direct= 相关),我假设我需要将 .queryset
属性 设置为colors
字段,但我不确定在哪里做。两个想法:
- 我猜它会以某种方式进入
.get_form_initial()
,但我不知道实现它的最佳方法。 - 或者,适当的代码可能会以某种方式进入
productFormWizard.get_context_data()
方法。
在 .get_form_initial() 中,我可以这样做:
if step == '1':
itemID = self.storage.get_step_data('0').data.get('0-pfProduct', "")
if itemID:
obj = CatalogItem.objects.get(id=itemID)
initial['colors'] = obj.get_get_colors()
但是,这只是选择可用的相关项目...它不会限制列表。
附加信息
Python == 3.5.3
Django == 1.10.6
django-crispy-forms == 1.6.1
django-formtools == 2.0
解决方案是覆盖视图上的 .get_form()
方法:
def get_form(self, step=None, data=None, files=None):
form = super(bzProductFormWizard, self).get_form(step, data, files)
if step == '1':
past_data = self.get_cleaned_data_for_step('0')
product = past_data['product']
form.fields['colors'].queryset = ... #CUSTOM QUERYSET
return form