【问题标题】:Using a list to populate model form foreign key in django在 django 中使用列表填充模型形式的外键
【发布时间】:2012-08-30 16:31:58
【问题描述】:

我正在尝试使用列表来限制我的 modelform 外键实例:

这是我的模型:

class Voicemail(models.Model):
    internalline = models.ForeignKey(InternalLine)
    person = models.ForeignKey(Person)

然后在我有相应模型形式的init方法中

class VoicemailForm(ModelForm):
 def __init__(self, *args, **kwargs):
  ....
  ....
 # self.fields['internalline'].queryset = self.person.getPersonLines()  # this throws error in template.
   self.fields['internalline'].queryset = self.person.line.all()

   print(self.person.getPersonLines())
   print(self.person.line.all())

两个打印输出相同的输出:

[<InternalLine: 1111>, <InternalLine: 5555>]
[<InternalLine: 1111>, <InternalLine: 5555>]

在 getPersonLines 中,我做了一些额外的逻辑并返回一个行列表:

def getPersonLines(self):
    lines = []
    for line in self.line.order_by('extension'):
        lines.append(line)
    for phone in self.phonesst_set.all():
        for line in phone.line.order_by('extension'):
            if line not in lines:               
                lines.append(line)   

    return lines

现在当我尝试在模板中渲染时,如果我使用 getPersonLines 返回的列表,我会得到错误,

Caught AttributeError while rendering: 'list' object has no attribute 'all'

但如果我使用 self.person.line.all().. 填充查询集,同样的事情会起作用。

我在尝试使用列表填充我的查询集时是否遗漏了什么?

提前致谢!!

更新

这是堆栈跟踪

self.fields['internalline'].choices = self.person.getPersonLines()  

Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Python26\lib\site-packages\django\utils\encoding.py", line 27, in __str__
    return self.__unicode__().encode('utf-8')
File "C:\Python26\lib\site-packages\django\forms\forms.py", line 95, in __unicode__
    return self.as_table()
File "C:\Python26\lib\site-packages\django\forms\forms.py", line 217, in as_table
    errors_on_separate_row = False)
File "C:\Python26\lib\site-packages\django\forms\forms.py", line 180, in _html_output
   'field': unicode(bf),
File "C:\Python26\lib\site-packages\django\forms\forms.py", line 408, in __unicode__
   return self.as_widget()
File "C:\Python26\lib\site-packages\django\forms\forms.py", line 439, in as_widget
   return widget.render(name, self.value(), attrs=attrs)
File "C:\Python26\lib\site-packages\django\forms\widgets.py", line 516, in render
   options = self.render_options(choices, [value])
File "C:\Python26\lib\site-packages\django\forms\widgets.py", line 533, in render_options
for option_value, option_label in chain(self.choices, choices):
TypeError: 'InternalLine' object is not iterable

更新 2:

这是整个__init__方法

class VoicemailForm(ModelForm):

def __init__(self, *args, **kwargs):
   try: 
        self.person = kwargs.pop('person', None)
        super(VoicemailForm, self).__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].widget.attrs['class'] = 'required_field'

        print(self.person.getPersonLines())
        print(self.person.line.all())
        if self.person:
            self.fields['internalline'].choices = self.person.getPersonLines()  
            #self.fields['internalline'].queryset = self.person.line.all()

   except Exception as e:
       print("Error overwriting __init__ of VoicemailForm")
       print(e)    

这就是我的表单名称

voicemail = VoicemailForm(person=person, prefix='voicemail')

更新 3 我尝试按如下方式创建 django 表单:

class test(forms.Form):
 line = forms.ChoiceField()
 def __init__(self, *args, **kwargs):
        super(test, self).__init__(*args, **kwargs)
        self.fields['line'].choices=person.getPersonLines()

但我继续收到同样的错误 for option_value, option_label in chain(self.choices, choices): TypeError: 'InternalLineSST' object is not iterable

然后我厌倦了这样的事情:

test = [1,2,3]
class myform(forms.Form):
    line = forms.ChoiceField()
    def __init__(self, *args, **kwargs):
        super(myform, self).__init__(*args, **kwargs)
        self.fields['line'].choices = test

>>> form = myform()
>>>print(form)

这给了我类似的错误

File "C:\Python26\lib\site-packages\django\forms\forms.py", line 439, in as_widget
 return widget.render(name, self.value(), attrs=attrs)
File "C:\Python26\lib\site-packages\django\forms\widgets.py", line 516, in render
 options = self.render_options(choices, [value])
File "C:\Python26\lib\site-packages\django\forms\widgets.py", line 533,in render_options
for option_value, option_label in chain(self.choices, choices):
TypeError: 'int' object is not iterable`

我错过了什么吗?

【问题讨论】:

    标签: django django-models django-forms django-templates


    【解决方案1】:

    .all().order_by() 方法都是 Django 查询集的一部分。它们与 Python 列表不同。虽然表示相同,但​​它们确实不同。

    Django ModelChoiceField 中的某些代码确实希望外键具有查询集而不是结果列表。如果你改为设置self.fields['internalline'].choices,就不会出现这个问题。

    所以试试这个吧:

    self.fields['internalline'].choices = self.person.getPersonLines()
    

    【讨论】:

    • 感谢您的快速响应,当我尝试在渲染时收到错误 Caught TypeError: 'InternalLine' object is not iterable 这就是我在模板 {{ voicemail }} 中渲染的方式
    • @akotian:你能提供那个错误的堆栈跟踪吗?我想知道那里发生了什么。
    • 这毫无意义...设置.choices 属性会调用ChoiceField 上的_set_choices() 方法。该方法强制输入是一个列表,因此是可迭代的。你能显示你表单的整个__init__ 方法吗?它必须在访问self.field之前初始化父级
    • 我添加了 __init__ 方法,作为更新。再次感谢!!
    • @akotian:查看代码这应该是不可能的,但是......我们可以进一步尝试:) 如果你给表单一个internalline = forms.ChoiceField() 属性怎么办?这样我们至少可以确定这不是一个奇怪的模型形式的东西。
    【解决方案2】:

    我使用列表的目的是我想合并两个查询集以显示外键选项。

    基于

    https://groups.google.com/forum/?hl=en&fromgroups=#!topic/django-users/0i6KjzeM8OI

    我修改了我的方法以返回查询集而不是列表:

    def getPersonLines(self):
        vm_lines = self.line.all()
        for phone in self.phonesst_set.all():
            vm_lines = vm_lines | phone.line.all()
    

    并且在表单的__inti__ 方法中,我可以使用查询集

    self.fields['internalline'].queryset = self.person.getPersonLines()
    

    【讨论】:

      猜你喜欢
      • 2012-10-21
      • 2018-06-26
      • 1970-01-01
      • 2010-10-06
      • 2020-11-16
      • 2020-09-23
      • 1970-01-01
      • 2012-12-23
      • 1970-01-01
      相关资源
      最近更新 更多