【问题标题】:Django Forms; Overiride choices with ModelFormDjango 表单;使用 ModelForm 覆盖选择
【发布时间】:2018-12-17 07:29:48
【问题描述】:

我想要做的是根据页面隐藏或显示一些选择。 例如,

models.py

USA = 'usa'
FRANCE = 'france'
CHINA = 'china'
GERMANY = 'germany'
SPAIN = 'spain'

TOPICS = (
    (USA, 'USA'),
    (FRANCE, 'France'),
    (CHINA, 'China'),
    (GERMANY, 'Germany'),
    (SPAIN, 'Spain'),
        )

topic = models.CharField(
    choices=TOPICS,
    default=USA,
    )

对于一个页面,我想强制用户不要选择 USA,所以我想在表单中隐藏 USA 并更改默认值。我该怎么做?

这是我当前的代码。 类 AForm(forms.ModelForm):

    class Meta:
        model = A
        fields = ['topic',]

    def __init__(self, *args, **kwargs):


        super().__init__(*args, **kwargs)

                self.fields['topic'].choices = ['France', 'Germany', 'Spain']

有一个错误。

ValueError:解包的值太多(预计 2 个)

我将其替换为随机的两个字符,例如ab,其中一个字符作为选项出现在表单上,​​即使我没有在模型上定义它。我仍然不明白如何将覆盖的选项与模型相关联。 ModelForm 的正确方法是什么?

【问题讨论】:

  • __init__ 中,您可以通过self.fields['topic'].choices 进行操作。

标签: python django django-forms


【解决方案1】:

这与 ModelForm 无关,但与如何定义选择有关 - 选择应该是 (value, label) 元组的列表(查看您如何在模型中定义选择),而不是值列表。你想要的是:

self.fields['topic'].choices = [
  ('france','France'), 
  ('germany', 'Germany'), 
  ('spain', 'Spain')
  ]

或(更好):

self.fields['topic'].choices = [
   choice for choice in YourModel.TOPICS
   if choice[0] in ('france', 'germany', 'spain')
   ]

【讨论】:

    【解决方案2】:

    正如 Pjot 在 cmets 中所说,您可以在表单的 __init__ 方法上动态填充值

    # put this two on the top of your forms.py, remove them later if you wish
    from pprint import pprint
    logger = logging.getLogger(__name__)
    
    class YourForm(Form):
        # you may set an empty choices list here, we'll override it later
        a_choicefield = ChoiceField(label="My choice field", choices=[('', '---------')])
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
            # add this log output to inspect the inner guts of your Form/ModelForm
            logger.warn(pprint(vars(self)))
    
            # here you may get params from args or kwargs comming from elsewhere
            # so you may fill the choices list accordingly
    
            my_dynamic_choices = []
    
            if kwargs['foo']:
                my_dynamic_choices = [A, B, C]
            else:
                my_dynamic_choices = [C, D, E]
    
            self.fields['a_choicefield'] = ChoiceField(label="My choice field", choices=my_dynamic_choices)
    

    【讨论】:

    • 如何使用ModelForm 做到这一点?我试过这种方式,但有一个像ModelForm 这样的AttributeError 没有fields
    • @dude 据我所知,您可以像使用任何其他表单一样,确保在 super().__init__(*args, **kwargs) 之后执行此操作,实际上我在几个项目中使用 ModelForms 做了很多。
    • 我看到的唯一问题是您在模型和__init__ 方法中都使用了 CharField,我想我们一直在谈论 ChoiceFields,对吗?这可能是 AttributeError 的原因吗?
    • 没有错误,但该字段不显示。此外,当我使用“ChoiceField”时,也会出现错误。我认为它是由Form 对象给出的,而不是ModelForm
    • 让我们再尝试一件事:将这两个添加到您的 forms.py 的顶部,紧随最后一次导入之后:from pprint import pprint logger = logging.getLogger(__name__) 然后在 init logger.warn(pprint(vars(self))) 中的 super 之后添加这两个@ 然后检查 django 开发服务器控制台中显示的字段
    【解决方案3】:

    我找到了一种简单的方法。可以这样覆盖。

    self.fields['field_name'].choices = list(self.fields['field_name'].choices)[:3]
    

    【讨论】:

      猜你喜欢
      • 2012-01-31
      • 2016-03-20
      • 2015-03-15
      • 2012-04-10
      • 1970-01-01
      • 2019-08-08
      • 2018-11-23
      • 1970-01-01
      • 2018-02-01
      相关资源
      最近更新 更多