Django动态替换ModelForm实例或不保存Form数据[image]

时间:2013-05-14 03:03:44

标签: django django-admin django-forms

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

问题

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

如果在重新分配字段中提交了品牌,我想将Brands.company设置为父formset值,并在不尝试保存ModelForm的情况下静默返回。

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

一张图片说了千言万语......

enter image description here

代码

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

1 个答案:

答案 0 :(得分: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