django - Как перепроверить ModelAdmin, и встраивает?

У меня есть две модели (ModelParent и ModelChild) с теми же m2m полями на модели Subject. ModelChild имеет внешний ключ на ModelParent, и ModelChild определяется как встроенный для ModelParent на администраторской странице.

### 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)

У меня есть одно важное ограничение, хотя, subjects_child поле ModelChild не должно ссылаться ни на какой предмет, который subject_parent делает с его subjects_parent.

Так, если я выбираю тот же Предмет (в subject_parent и subject_child) на странице Admin для обеих моделей, как я могу проверить это? Если только одно полевое изменение Вы проверяете его против дб, но что если и изменение (subject_parent и subject_child)? Как я могу проверить обе формы вместе перед сохранением?

6
задан blaztinn 27 April 2010 в 10:29
поделиться

2 ответа

Я унаследовал новый класс с именем ModelAdminWithInline от admin.ModelAdmin и модифицировал методы add_view (...) и change_view (...) для вызова функции is_cross_valid (self, form, formsets), где вы можете проверить все формы вместе. Обе функции были:

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

изменены на:

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

Новая функция is_cross_valid (...) определяется следующим образом:

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

, поэтому новый класс должен работать точно так же, как ModelAdmin, если вы не измените функцию is_cross_valid (...).

Теперь мой admin.py выглядит так:

###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)

Решение немного хакерское, но работает :). Ошибки проявляются так же, как и в обычных классах ModelForm и ModelAdmin. Django 1.2 (который должен быть выпущен в ближайшее время) должен иметь валидацию модели, поэтому я надеюсь, что тогда эту проблему можно будет решить лучше.

5
ответ дан 17 December 2019 в 00:05
поделиться

Классы admin не имеют метода clean(). Их формы это делают. Каждый класс администратора имеет параметр form. Вы просто расширяете форму по умолчанию (это обычная форма ModelAdmin), реализуете метод clean() и добавляете форму в класс admin. Пример:

class SomeForm(ModelForm):
  #some code
  def clean(self):
   #some code
class SomeAdminClass(ModelAdmin):
 #some code
 form = SomeForm
 #more code
2
ответ дан 17 December 2019 в 00:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: