gpt4 book ai didi

Django ModelForm: Insert blank choice into many form fields(Django ModelForm:在多个表单域中插入空白选项)

转载 作者:bug小助手 更新时间:2023-10-25 12:26:17 30 4
gpt4 key购买 nike



In order to be sure I force users to pick a valid value from a dropdown (rather than unknowingly leaving the first option in the list set without changing it to the correct value), I am inserting the blank choice field in many required form fields.

为了确保强制用户从下拉列表中选择一个有效的值(而不是无意中保留列表集中的第一个选项而不将其更改为正确的值),我在许多必填表单域中插入了空白的选项域。


models.py

Models.py


class MyModel(models.Model):
gender = models.CharField(max_length=1, null=True, blank=False, choices=GENDER_CHOICES, default='')

Original forms.py (Explicitly defining the form field. This works.)

原始forms.py(显式定义表单域。这是可行的。)


from django.db.models.fields import BLANK_CHOICE_DASH
class MyForm(forms.ModelForm):
gender = forms.TypedChoiceField(required=True, choices=BLANK_CHOICE_DASH+MyModel._meta.get_field('gender').choices)
class Meta:
model = MyModel
fields = '__all__'

Now, because I am doing this for many fields, I tried to revise my earlier code in forms.py:

现在,因为我要对许多字段执行此操作,所以我尝试在forms.py中修改前面的代码:


Revised forms.py (Setting the choices in __init__(). Does not work.)

修订了forms.py(在__init__()中设置选项。不起作用)。


class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
for type in ('gender', ...):
self.fields[type].choices.insert(0, (u'',u'---------' ))
# Not needed anymore.. replaced by code in __init__()
# gender = forms.TypedChoiceField(required=True, choices=BLANK_CHOICE_DASH+MyModel._meta.get_field('gender').choices)
class Meta:
model = MyModel
fields = '__all__'

In this case, I do not get the dashes as the first choice in the dropdown.

在本例中,我没有将破折号作为下拉列表中的第一选择。


I tried to look into the problem by using pdb in the template to inspect the form field right before it was outputted. The debugger shows element.field.choices to be (u'', u'---------'), ('f', 'Female'), ...] in both cases. Nevertheless, the code that outputs the form field inserts the dashes only in the original code, not in the revised code.

我试图通过在模板中使用PDB在输出之前检查表单域来研究这个问题。调试器显示element.field。选项为(u‘’,u‘-’),(‘f’,‘Female’),...]在这两种情况下。但是,输出表单域的代码只在原始代码中插入破折号,而不在修订后的代码中插入。


I tried stepping through the Django code that renders the form field to figure out if it was using some other field besides .choices that I'm not aware of, but I never stepped into the right part of the code.

我尝试单步执行呈现表单域的Django代码,以确定它是否使用了我不知道的其他字段,但我从未进入代码的正确部分。


How can I accomplish this? Although it works fine the first way, the revised code is much more DRY. If only I could make it work!

我怎样才能做到这一点呢?尽管第一种方法运行良好,但修订后的代码要枯燥得多。要是我能让它起作用就好了!


更多回答

Is there a reason you aren't just using the built-in empty_label?

为什么不使用内置的EMPTY_LABEL呢?

@solarissmoke Because the empty choice isn't showing up by default because of the way the model is written. Hence the need to force in the empty choice.

@solarismoke,因为由于模型的编写方式,默认情况下不会显示空选项。因此,有必要强行做出空洞的选择。

优秀答案推荐

This appears to be a bug in ChoiceWidget.__deepcopy__().

这似乎是ChoiceWidget.__DeepCopy__()中的错误。


These work:

这些工作包括:


# self.fields[name].choices.insert(0, (u'', u'---------'))
self.fields[name].widget.choices.insert(0, (u'', u'---------'))
# or
self.fields[name].choices = BLANK_CHOICE_DASH + self.fields[name].choices

Explanation


TypedChoiceField.choices, inherited from ChoiceField, is a property:

从ChoiceField继承而来的TyedChoiceField.Chotions是一个属性:



class TypedChoiceField(ChoiceField):

class ChoiceField(Field):
...

def _get_choices(self):
return self._choices

def _set_choices(self, value):
# Setting choices also sets the choices on the widget.
# ...
if callable(value):
value = CallableChoiceIterator(value)
else:
value = list(value)

self._choices = self.widget.choices = value

choices = property(_get_choices, _set_choices)



  • _set_choices() assigns self.widget.choices in addition to self._choices.

    • The widget choices is the one used in the rendering.

    • The widget choices is supposed to be the same instance as that in the field.




The field and widget are deepcopy'ed as follows:

字段和小工具的深度复制如下:



class ChoiceField(Field):
widget = Select
...

def __deepcopy__(self, memo):
result = super().__deepcopy__(memo)
result._choices = copy.deepcopy(self._choices, memo)
return result

class Select(ChoiceWidget):

class ChoiceWidget(Widget):
...

def __deepcopy__(self, memo):
obj = copy.copy(self)
obj.attrs = self.attrs.copy()
obj.choices = copy.copy(self.choices)
memo[id(self)] = obj
return obj



  • ChoiceWidget.__deepcopy__() does not memoize the copy of self.choices.

    • The copy of choices is then unavailable to the deepcopy in ChoiceField.

    • The widget choices is no longer the same instance as that in the field.




更多回答

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com