Django 1.x & form_for_model
by Larin
Интро
Давным-давно, когда деревья были большими, “джанга” маленькой, а формы “новыми”, существовала такая функция: form_for_model. И на основе этой функции был даже создан сниппет, позволяющий динамический создавать форму по модели и менять “на лету” свойства созданной формы.
Однако, начиная с версии Django 1.0 данная функциональность была помечена как “deprecated” и уже в 1.0 beta 1 удалена.
Еще проще
В новой версии просто советуют использовать наследников класса ModelForm.
В одном из проектов мне понадобилось создавать формы по моделям, динамически. Моделей много, формы почти однотипные. Вот это “почти” и заставило искать решение – как просто изменить один (или несколько) виджетов у динамически созданной формы?
Вот, что у меня получилось:
def form_for_model(model, fields=None, widgets=None):
""" Динамическое создание формы по моделе. """
class Meta:
pass
setattr(Meta, 'model', model)
if widgets:
setattr(Meta, 'widgets', widgets)
attrs = { '__module__': '', 'Meta': Meta, }
if fields:
attrs.update(fields)
name = '%sForm' % model.__name__
return type(name, (ModelForm,), attrs)
Пример использования:
#-- models.py
class Book(models.Model):
title = models.CharField(maxlength = 100)
description = models.TextField()
author = models.ForeignKey(Author)
#-- views.py
def add_book(request):
custom_fields = dict(
owner = AutocompleteField()
)
custom_widgets = dict(
name = forms.TextInput({"size": 70}),
description = RichTextarea()
)
form_inst = form_for_model(Book, fields=custom_fields, widgets=custom_widgets)
form = form_inst(request.POST or None)
if form.is_valid():
form.save()
return locals()
Alpha
Код еще можно доработать до полной универсальности, чтобы можно было “повторить” конструкцию вида:
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
exclude = ('birth_date',)
но для моей задачи этого не требовалось.