1

数据输入人员不断添加和复制模型,因为他们无法轻松搜索现有的内联项目,因此我在 Brand ModelForm 中添加了字段以允许自动建议 Brand 模型。

问题

Brand.name 是 Brand 模型的必填字段。因此,当仅填写 Autocomplete 字段时(在将现有品牌重新分配给当前公司的情况下), form.save() 失败(它为空,但 save() 需要 Brand.name ,无论如何我都不需要不想将表单保存为模型实例,因为我刚刚重新分配了)。

如果在重新分配字段中提交了品牌,我只想将该 Brands.company 设置为父表单集值,然后静默返回而不尝试保存 ModelForm。

该关系是从品牌模型到公司模型的外键——一个公司可能有很多品牌。

一张图说一千个字,所以...

在此处输入图像描述

代码

class BrandAdminForm(forms.ModelForm):
    reassign_existing = AutoCompleteSelectField('brand', required=False,)
    confirm_reassign = BooleanField(required=False, help_text=_("Are you sure you want to reassign the brand?"))

    def __init__(self, *args, **kwargs):
        super(BrandAdminForm, self).__init__(*args, **kwargs)
        self.fields['name'].required = False

    def clean(self):
        cleaned_data = super(BrandAdminForm, self).clean()
        import ipdb; ipdb.set_trace()

        if cleaned_data['reassign_existing'] \
                and cleaned_data['confirm_reassign'] \
                and not self.instance.pk:
            self.instance = cleaned_data['reassign_existing']
            cleaned_data['reassign_existing'].company = self.instance.company
            cleaned_data['id'] = self.instance.id
            cleaned_data['category'] = self.instance.category.all()
            cleaned_data['website'] = self.instance.website
            cleaned_data['twitter_handle'] = self.instance.twitter_handle
            cleaned_data['wikipedia_uri'] = self.instance.wikipedia_uri
            cleaned_data['email'] = self.instance.email
            cleaned_data['name'] = self.instance.name
            return cleaned_data
        elif cleaned_data['reassign_existing'] \
                and cleaned_data['confirm_reassign'] \
                and self.instance.pk:
            raise forms.ValidationError("You can't reassign AND add/edit a brand in the same form. Clear one of the sections.")
        else:
            if not cleaned_data['name']:
                msg = u"You must add a name to a new brand."
                self._errors["name"] = self.error_class([msg])
            return cleaned_data
    class Meta:
        model = Brand

这种方法几乎有效,只有在重新分配品牌的类别时才会列出。这是M2M领域。

编辑 1

当'reassign_existing'中有值时,我试图覆盖保存以不保存但最终得到一个

'NoneType' object has no attribute 'company_id'

这是设置

class BrandAdminForm(forms.ModelForm):
reassign_existing = AutoCompleteSelectField('brand', required=False,
                                            )
confirm_reassign = BooleanField(required=False, help_text=_("Are you sure you want to reassign the brand?"))

def __init__(self, *args, **kwargs):
    super(BrandAdminForm, self).__init__(*args, **kwargs)
    self.fields['name'].required = False

def clean(self):
    cleaned_data = super(BrandAdminForm, self).clean()

    if cleaned_data['reassign_existing'] \
            and cleaned_data['confirm_reassign'] \
            and not self.instance.pk:
        cleaned_data['reassign_existing'].company = self.instance.company
        cleaned_data['reassign_existing'].save()
        return cleaned_data
    elif cleaned_data['reassign_existing'] \
            and cleaned_data['confirm_reassign'] \
            and self.instance.pk:
        raise forms.ValidationError("You can't reassign AND add/edit a brand in the same form. Clear one of the sections.")
    else:
        if not cleaned_data['name']:
            msg = u"You must add a name to a new brand."
            self._errors["name"] = self.error_class([msg])
        return cleaned_data

def save(self, *args, **kwargs):
    if not self.cleaned_data['reassign_existing']:
        super(BrandAdminForm, self).save(*args, **kwargs)

class Meta:
    model = Brand
4

1 回答 1

1

这是我想出的解决方案。需要继承 ModelForm 和 BaseFormsetInline

class BrandBaseFormSet(BaseInlineFormSet):
def save_new(self, form, commit=True):
    import ipdb;ipdb.set_trace()
    if form.cleaned_data['reassign_existing'] \
            and form.cleaned_data['confirm_reassign'] \
            and not form.instance.pk:
        return form.cleaned_data['reassign_existing']
    else:
        import ipdb;ipdb.set_trace()
        return super(BrandBaseFormSet, self).save_new(form, commit=commit)

class BrandAdminForm(forms.ModelForm):
"""
Allow for reassigning of reverse fk relationships inline of the child.
"""
reassign_existing = AutoCompleteSelectField('brand', required=False)
confirm_reassign = BooleanField(required=False)

def __init__(self, *args, **kwargs):
    super(BrandAdminForm, self).__init__(*args, **kwargs)
    self.fields['name'].required = False

def clean(self):
    """
    Here we check if its a new form or reassigning an existing brand. If its reassigning, we just do that in
    this method.
    :return: cleaned form data
    """
    cleaned_data = super(BrandAdminForm, self).clean()
    if cleaned_data['reassign_existing'] \
            and cleaned_data['confirm_reassign'] \
            and not self.instance.pk:
        cleaned_data['reassign_existing'].company = self.instance.company
        cleaned_data['reassign_existing'].save()
        return cleaned_data
    elif cleaned_data['reassign_existing'] \
            and cleaned_data['confirm_reassign'] \
            and self.instance.pk:
        raise forms.ValidationError("You can't reassign AND add/edit a brand in the same form. Clear one of the sections.")
    else:
        if not cleaned_data['name']:
            msg = u"You must add a name to a new brand."
            self._errors["name"] = self.error_class([msg])
        return cleaned_data

def save(self, *args, **kwargs):
    if not self.cleaned_data['reassign_existing']:
        return super(BrandAdminForm, self).save(*args, **kwargs)
    else:
        return self.cleaned_data['reassign_existing']

class Meta:
    model = Brand
于 2013-05-14T05:17:54.480 回答