django - 如何交叉检查ModelAdmin及其内联? [英] django - How to cross check ModelAdmin and its inlines?

查看:143
本文介绍了django - 如何交叉检查ModelAdmin及其内联?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个模型(ModelParent和ModelChild),在主题模型上具有相同的m2m字段。
ModelChild在ModelParent上有一个外键,ModelChild在管理页面上定义为ModelParent的内联。

  ### model.py ### 
class Subject(Models.Model):
pass

class ModelParent(models.Model):
subjects_parent = ManyToManyField(Subject)

class ModelChild(models.Model):
parent = ForeignKey(ModelParent)
subjects_child = ManyToManyField(Subject)

### admin.py# ##
class ModelChildInline(admin.TabularInline):
model = ModelChild

class ModelParentAdmin(admin.ModelAdmin):
inlines = [ModelChildInline]

admin.site.register(ModelParent,ModelParentAdmin)

我有一个重要的限制, ModelChild的subjects_child字段不得引用subject_parent与其subject_parent的任何主题。



所以,如果我在A上选择相同的主题(在subject_parent和subject_child中)这两个模型的dmin页面,我该如何验证?
如果只有一个字段更改,则会对该数据库进行验证,但是如果两者都更改(subject_parent和subject_child)呢?
如何在保存之前一起验证两个表单?

解决方案

我从管理员继承了一个名为ModelAdminWithInline的新类。 ModelAdmin和修改的方法add_view(...)和change_view(...)调用函数is_cross_valid(self,form,formsets),您可以将所有表单一起验证。
这两个函数都有:

 #... 
如果all_valid(formsets)和form_validated:
#...

更改为:





formets_validated = all_valid(formsets)
cross_validated = self.is_cross_valid(form,formsets)
如果formsets_validated和form_validated和cross_validated :
#...

新功能is_cross_valid(...)被定义为这是:

  def is_cross_valid(self,form,formsets):
return True

所以如果不更改is_cross_valid(...)函数,新类应该与ModelAdmin完全相同。



现在我的admin.py看起来像这样:

  ### admin.py 


$ b def add_view(self,request, form_url ='',extra_context = None):
#modified code

def change_view(self,request,object_id,extra_context = None):
#modified code

class ModelChildInline(admin.TabularInline):
model = ModelChild

class ModelParentAdmin(ModelAdminWithInline):
inlines = [ModelChildInline]

def is_cross_valid(self,form,formsets):
#do表单上的一些交叉验证
#例如,这里是我的特定验证:
valid = True

如果hasattr(form,'cleaning_data'):

subjects_parent = form.cleaned_data.get(subjects_parent)

#您可以从这样的窗体访问窗体:
for formset中的formset:
for formset_form in formset.forms:
if hasattr(formset_form,'cleaning_data'):

subjects_child = formset_form.cleaned_data.get(subjects_child)
delete_form = formset_form.cleaned_data.get( DELETE)

如果su bjects_child和(delete_form == False):
对于subject_child中的主题:
如果subject_parent中的主题:
valid = False
#From这里您仍然可以报告错误,如常规表单:
如果formset_form.cleaned_data.keys()中的subjects_child:
formset_form._errors [subjects_child] = ErrorList([u主体%s已在父ModelParent中被选择%subject])
del formset_form.cleaned_data [subjects_child]
else:
formset_form._errors [subjects_child] + = ErrorList(u主体%s已在父ModelParent中选择%subject] )

#return成功为True,否则为False。
返回有效

admin.site.register(ModelParent,ModelParentAdmin)

解决方案有点黑客,但它的作品:)。错误显示与常规ModelForm和ModelAdmin类相同。 Django 1.2(应该很快发布)应该有模型验证,所以我希望这个问题可以更好地解决。


I have two models (ModelParent and ModelChild) with same m2m fields on Subject model. ModelChild has a foreign key on ModelParent and ModelChild is defined as inline for ModelParent on admin page.

### models.py ###
  class Subject(Models.Model):
    pass

  class ModelParent(models.Model):
    subjects_parent = ManyToManyField(Subject)

  class ModelChild(models.Model):
    parent = ForeignKey(ModelParent)
    subjects_child = ManyToManyField(Subject)

### admin.py ###
  class ModelChildInline(admin.TabularInline):
      model = ModelChild

  class ModelParentAdmin(admin.ModelAdmin):
    inlines = [ModelChildInline]

  admin.site.register(ModelParent, ModelParentAdmin)

I have one important restriction though, ModelChild's subjects_child field must not reference any subject that subject_parent does with its subjects_parent.

So, if I select the same Subject (in subject_parent and subject_child) on Admin page for both models, how can I validate this? If only one field changes you validate it against the db, but what if both change (subject_parent and subject_child)? How can I validate both forms together before saving?

解决方案

I have inherited a new class named ModelAdminWithInline from admin.ModelAdmin and modified methods add_view(...) and change_view(...) to call function is_cross_valid(self, form, formsets), where you can validate all the forms together. Both functions had:

#...
if all_valid(formsets) and form_validated:
#...

changed to:

#...
formsets_validated = all_valid(formsets)
cross_validated = self.is_cross_valid(form, formsets)
if formsets_validated and form_validated and cross_validated:
#...

The new function is_cross_valid(...) is defined like this:

def is_cross_valid(self, form, formsets):
  return True

so the new class should work exactly the same as ModelAdmin if you don't change is_cross_valid(...) function.

Now my admin.py looks like this:

###admin.py###
class ModelAdminWithInline(admin.ModelAdmin):
  def is_cross_valid(self, form, formsets):
    return True

  def add_view(self, request, form_url='', extra_context=None):
    #modified code

  def change_view(self, request, object_id, extra_context=None):
    #modified code

class ModelChildInline(admin.TabularInline):
  model = ModelChild

class ModelParentAdmin(ModelAdminWithInline):
  inlines = [ModelChildInline]

  def is_cross_valid(self, form, formsets):
    #Do some cross validation on forms
    #For example, here is my particular validation:
    valid = True

    if hasattr(form, 'cleaned_data'):   

      subjects_parent = form.cleaned_data.get("subjects_parent")

      #You can access forms from formsets like this:
      for formset in formsets:
        for formset_form in formset.forms:
          if hasattr(formset_form, 'cleaned_data'):

            subjects_child = formset_form.cleaned_data.get("subjects_child")
            delete_form = formset_form.cleaned_data.get("DELETE")

            if subjects_child and (delete_form == False):
              for subject in subjects_child:
                if subject in subjects_parent:
                  valid = False
                  #From here you can still report errors like in regular forms:
                  if "subjects_child" in formset_form.cleaned_data.keys():
                    formset_form._errors["subjects_child"] = ErrorList([u"Subject %s is already selected in parent ModelParent" % subject])
                    del formset_form.cleaned_data["subjects_child"]
                  else:
                    formset_form._errors["subjects_child"] += ErrorList(u"Subject %s is already selected in parent ModelParent" % subject])

      #return True on success or False otherwise.
      return valid

admin.site.register(ModelParent, ModelParentAdmin)

The solution is a little bit hackish but it works :). The errors show up the same as with regular ModelForm and ModelAdmin classes. Django 1.2 (which should be released shortly) should have model validation, so I hope that then this problem could be solved more nicely.

这篇关于django - 如何交叉检查ModelAdmin及其内联?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆