2014-09-16 3 views
0

У меня есть несколько MyModels, все они получены из одного и того же MyBaseModel, и для каждой модели есть также MyModelForm, полученный из MyModelBaseForm. Учитывая MyModelForm, я могу получить доступ к связанной модели через MyModelForm._meta.model. Что было бы самым простым способом сделать обратное: учитывая MyModel, получите соответствующий MyModelForm?Django register ModelForm с моделью

Причина в том, я хочу использовать утку набрав в представлении:

from django.db import models 

def edit_view(request, my_model_name, pk=None): 
    my_model = my_model_registry[my_model_name] 
    instance = get_object_or_404(my_model, pk=pk) if pk else None 
    my_model_form = my_model._meta.modelform 
    # or my_model_form = my_model_form_registry[my_model] 
    form = my_model_form(request.POST or None, instance=instance) 
    if form.is_valid(): 
     instance = form.save() 
     return HttpResponseRedirect(instance.get_absolute_url()) 
    return render(request, 'my_template', {'form': form, 'instance': instance}) 

my_model_registry = dict((Model._meta.verbose_name, Model) for Model in 
          models.get_models() if issubclass(Model, MyBaseModel) 
         ) 

Идеальным решением было бы иметь словарь my_model_form_registry[my_model], так что я могу смотреть на форму так же, как я делаю с моделью. Я знаю, что могу сделать это вручную, явно установив

my_model_form_registry[MyModelForm._meta.model] = MyModelForm 

после каждого определения MyModelForm, но в духе DRY, я хотел бы сделать это один раз для ModelBaseForm и он выполняется автоматически для всех производных моделей.

Метаклассы могут это сделать, но я не могу заставить это работать, потому что model.ModelForm уже имеет специальный метакласс.

Другой вариант был бы, если бы был эквивалент models.get_models, но для моделей моделей. Это существует?

ответ

3

В django.forms.models есть функция modelform_factory(), которая динамически создает класс ModelForm с учетом класса модели, который звучит так, будто он может делать то, что вы хотите.

+0

Это будет работать для простых модельных форм, но в моем случае я хочу типовые формы, чтобы получить из MyModelBaseForm для некоторых дополнительных функций, определенных в clean_field и чистых методах. –

+0

Как показано на этой ссылке, вы можете передать существующий класс формы в modelform_factory. –

+0

Вы правы, это видно на примере. Полная документация по modelform_factory находится здесь: https://docs.djangoproject.com/en/dev/ref/forms/models/ –

0

Я думаю, что я понял, как добавить Метакласс к MyModelBaseForm , что будет делать трюк:

class MyModelBaseForm(forms.ModelForm): 

    class __metaclass__(forms.ModelForm.__metaclass__): 
     """ 
     Metaclass to register the modelform with the model, 
     as model._meta.modelform. 
     """     

     def __init__(cls, name, bases, dic): 
      super(__metaclass__, cls).__init__(cls, name, bases, dic) 
      cls._meta.model._meta.modelform = cls 

    class Meta: 
     model = MyBaseModel 
     fields = [ ... ]