简体   繁体   English

Django表单; 使用ModelForm替代选择

[英]Django Forms; Overiride choices with ModelForm

What I want to do is to hide or show some of the choices depending on the page. 我想要做的是根据页面隐藏或显示一些选择。 For example, 例如,

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,
    )

For a page, I want to force users not to choose USA, so I want to hide USA in form and also change the default value. 对于页面,我想强制用户不要选择USA,所以我想以表格形式隐藏USA并更改默认值。 How can I do this? 我怎样才能做到这一点?

Here is my current code. 这是我当前的代码。 class AForm(forms.ModelForm): 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']

There is an error. 发生错误。

ValueError: too many values to unpack (expected 2) ValueError:太多值无法解包(预期2)

and I replaced it with random two characters like ab One of the characters appears on the form as a choice even though I didn't define it on model. 我将其替换为随机的两个字符,例如ab ,即使我没有在模型上定义它,也可以选择其中一个字符出现在表单上。 I still don't understand how I can associate the overriden choices with model. 我仍然不明白如何将覆盖的选择与模型相关联。 What is the correct way with ModelForm ? 使用ModelForm的正确方法是什么?

As Pjot said in the comments, you can fill the values dynamically on the __init__ method of the form 如Pjot在评论中所述,您可以在表单的__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)

I found an easy way to do it. 我找到了一种简单的方法。 Can override like this. 可以像这样覆盖。

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

This has nothing to do with ModelForm, but with how choices are defined - choices are expected to be a list of (value, label) tuples (look at how you defined the choices in your model), not a list of values. 这与ModelForm无关,但与选择的定义方式有关-选择应该是(value, label)元组的列表(请看您如何在模型中定义选择),而不是值的列表。 What you want is: 您想要的是:

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

or (better): 或更好):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM