禁用默认行为 - ModelForm选择填充了引用对象的窗口小部件选项

时间:2015-04-12 22:55:31

标签: python django django-models django-forms modelform

我在Django中使用基于模型的表单。所以它看起来像这样:

240 class EventDetailForm(NgFormValidationMixin, NgModelForm):
241   def __init__(self, *args, **kwargs):tha
242     super(EventDetailForm, self).__init__(*args, **kwargs)
243     self.fields['gallery'].queryset = Gallery.objects.none()
244     
245   class Meta:
246     model = Event
247     fields = ('title', 'description', 'end_date', 'start_date', 'gallery', 'cover_photo')
248     widgets = {
249       'title': forms.TextInput(attrs={
250         'editable-detail': '',
251       }),
252       'description': forms.TextInput(attrs={
253         'class': 'panel-body',
254         'id': 'event-description-editable',
255         'editable-detail': '',
256       }),
257       'cover_photo': SelectWithDefaultOptions(attrs={
258         'class': 'chosen-select-no-single',
259         'id': 'select-cover-photo',
260         'data-placeholder': 'Select Cover Photo',
261         'style': 'width: 200px;',
262         'tabindex': '-1',
263       }),
264       'start_date': DateTimeWidget(attrs = {
265         'class': 'datetimepicker col-xs-6',
266         'id': 'event-start-date-editable',
267         'editable-detail': '',
268       }),
269       'end_date': DateTimeWidget(attrs = {
270         'class': 'datetimepicker col-xs-6',
271         'id': 'event-end-date-editable',
272         'editable-detail': '',
273       }),
274       'gallery': SelectWithDefaultOptions(attrs={
275         'class': 'chosen-select-no-single',
276         'id': 'select-galley',
277         'data-placeholder': 'Select Gallery',
278         'style': 'width: 200px;',
279         'gallery-select': '',
280         'tabindex': '-1',
281         'organisator-profile-specific': '',
282       }
283     } 

所以会发生的是我的gallery和cover_photo选择小部件被两种类型的所有现有对象填充(因为它们实际上是其他模型的外键)。  我想要阻止它,正如你在第243行看到的那样,我试图删除当前的查询集(尝试使用相同的清理选项),这非常有效。问题是,你看到我使用我的自定义选择小部件,我在其中设置了一些默认选项。它看起来像这样:

 62 class SelectWithDefaultOptions(forms.Select):
 63   def __init__(self, attrs=None, choices=()):
 64     super(SelectWithDefaultOptions, self).__init__(attrs, choices)
 65 
 66     choices = ('', 'empty') + choices
 67     choices = ('None', 'no selection') + choices

问题在于,通过我上面提到的方法,我删除了这些值。 所以我告诉自己"好吧,我会得到所需的值,擦除所有值并放回首选的"。尝试了但事实证明,实际上Django放入的对象正在删除已经设置的对象。 (在init方法通过后添加默认值) 所以我想"好吧,如果我在小部件的初始化中设置choices =()(第274行),Django不应该在其上设置任何其他值,因为这将违反我的选择"所以我试了一下,但事实证明,Django实际上并不关心我想要的选择和行为。 还尝试设置字段' initial'财产,仍然没有结果。

那么,如何防止DJango默认将引用的对象放入我的选择列表中呢?

感谢。

2 个答案:

答案 0 :(得分:0)

widget中定义的Meta导致此问题。如果您刚将其移至__init__,则可以正常使用。首先更新您的小部件,行choices中的关键字def __init__(self, attrs=None, choices=())表示默认情况下的选项为空,但任何实例都可以覆盖它,并传入一些值。所以你需要明确地将它设置为空元组:

class SelectWithDefaultOptions(forms.Select):
    def __init__(self, attrs=None, choices=()):
        super(SelectWithDefaultOptions, self).__init__(attrs, choices)
        choices = () # explicitly setting choices to empty here
        choices += (('', 'empty'),)
        choices += (('None', 'no selection'),)
        self.choices = choices

现在更新您的表单,将小部件分配到gallery中的__init__字段,而不是Meta类:

class EventDetailForm(NgFormValidationMixin, NgModelForm):
    def __init__(self, *args, **kwargs):
        super(EventDetailForm, self).__init__(*args, **kwargs)
        self.fields['gallery'].widget = SelectWithDefaultOptions(attrs={
            'class': 'chosen-select-no-single',
            'id': 'select-galley',
            'data-placeholder': 'Select Gallery',
            'style': 'width: 200px;',
            'gallery-select': '',
            'tabindex': '-1',
            'organisator-profile-specific': '',
        }

    class Meta:
        model = Event
        fields = ('title', 'description', 'end_date', 'start_date', 'gallery', 'cover_photo')

或者您根本不需要任何自定义小部件。只需在表单__init__方法中设置选项,并将SelectWithDefaultOptions小部件名称替换为forms.Select中的Meta(这更简洁,更简洁):

class EventDetailForm(NgFormValidationMixin, NgModelForm):
    def __init__(self, *args, **kwargs):
        super(EventDetailForm, self).__init__(*args, **kwargs)
        self.fields['gallery'].widget.choices = (('', 'Empty',),)

    class Meta:
        model = Event
        fields = ('title', 'description', 'end_date', 'start_date', 'gallery', 'cover_photo')
        widgets = {
            'gallery': forms.Select(attrs={
                'class': 'chosen-select-no-single',
                'id': 'select-galley',
                'data-placeholder': 'Select Gallery',
                'style': 'width: 200px;',
                'gallery-select': '',
                'tabindex': '-1',
                'organisator-profile-specific': '',
            }),
        }

答案 1 :(得分:0)

这是我修复它的方法,在@AamirAdnan:

的帮助下
 65 class SelectWithDefaultOptions(forms.Select):
 66   def render(self, name, value, attrs=None, choices=()):
 67     choices = ()
 68     choices += (('empty', ''),)
 69     choices += (('no selection', 'None'),)
 70     self.choices = choices
 71    
 72     if value is None:
 73         value = ''
 74    
 75     final_attrs = self.build_attrs(attrs, name=name)
 76     output = [format_html('<select{0}>', flatatt(final_attrs))]
 77     options = self.render_options((), [value])
 78     
 79     if options:
 80         output.append(options)
 81         output.append('</select>')
 82         
 83     return mark_safe('\n'.join(output))

刚刚改进了小部件渲染功能。

这不是所要求的,但它确实有效。会发生什么:
 1. Django将选择值设置为引用的对象
 2.在呈现窗口小部件之前,它们将更改为正确的选择