2013-05-14 46 views
1

数据输入人们不断添加和复制模型,因为他们无法轻松搜索现有的内嵌项目,所以我向Brand ModelForm添加了字段以允许自动提示品牌模式。Django动态替换ModelForm实例或不保存表单数据[image]

问题

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

如果品牌在重新分配字段中提交,我想只将Brands.company设置为父级表单集值,然后默默返回而不尝试保存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 
+0

编辑之后我不得不重写Formset保存新实例 – 2013-05-14 05:18:46

回答

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