Динамические требования к форме в Джанго - PullRequest
4 голосов
/ 09 февраля 2010

Я собираюсь начать большой проект Django на работе. И ключевые особенности - обработка формы. Там будет много форм, которые пользователи приложения будут использовать. И одним из требований является возможность редактирования форм в интерфейсе администратора приложения.

То есть не требуется добавлять / удалять поля формы. Но должна быть возможность редактировать атрибуты поля формы. Например, измените, какие поля являются обязательными и такими.

У кого-нибудь есть хорошие решения о том, как это сделать. Я думаю, что мне, возможно, придется разделить поля на подклассы, которые я хочу, чтобы они были динамическими и что-то там делать. Я предполагаю, что все поля моделей должны иметь «blank = True / null = True», и некоторые, как добавить мета-информацию в отдельную модель (?) О модели, которая объявляет, какие поля являются обязательными. А затем используйте эту информацию, когда формы отображаются и проверяются.

Прежде чем я начну заниматься этим, мне бы очень хотелось узнать, как разработать такое решение, у кого-нибудь есть идеи о том, как это должно быть сделано?


После дополнительных исследований я узнал, что вы можете сделать много с фабричными функциями, которые возвращали бы форму с заданным набором атрибутов. Похоже, проблема не так уж и сложна.

Я бы сделал функцию, которая возвращает форму с правильными установленными атрибутами / полями. Но часть, для которой я не нашел хорошего решения, состоит в том, как управлять этим в интерфейсе администратора. Я думаю, что я бы сделал db.Model, которая хранит информацию о полях других моделей. Где я могу установить, что требуется и такие.

А затем в функции, которая возвращает форму, перейдите через эту модель и верните форму с правильными атрибутами. Но как сделать эту модель (которая должна отражать поля других моделей) хорошим способом?

Ответы [ 2 ]

2 голосов
/ 09 февраля 2010

Это не точный ответ на вашу проблему, но я сделал что-то похожее, что я думаю, может быть полезно для вас. Я создал полностью настраиваемую форму, чтобы конечные пользователи могли настраивать ее.

Я получил 2 модели: BuiltForm и BuiltFormField:

class BuiltForm(models.Model): 
    name = models.CharField(max_length=32) 
    def form(self, data=None, initial=None):
        form = BuiltFormGenericForm(data, initial=initial)
        form.addBuiltFormFields(BuiltFormField.objects.filter(builtform=self, disabled=0))
        return form            

class BuiltFormField(models.Model):
    builtform = models.ForeignKey(BuiltForm)
    type = models.CharField(max_length=32, choices=ALL_FIELD_TYPES)
    label = models.CharField(max_length=32)
    fieldname = models.CharField(max_length=32)
    helptext = models.CharField(max_length=256, blank=True)
    required = models.BooleanField(default=False)
    sort_order = models.IntegerField(default=0)
    disabled = models.BooleanField(default=False)
    options = models.TextField(blank=True)
    def field(self):
        field = ALL_FIELD_MAPS.get(self.type)
        ## Build out the field, supplying choices, `required`, etc.

Есть несколько вещей, которые ненормальны. ALL_FIELD_TYPES - карта типов полей, разрешенных в форме. Это используется в сочетании с dict(), чтобы определить, какой класс (CharField, EmailField, ChoiceField и т. Д.) Следует использовать для этого поля. options также является pickle d списком параметров для последующего использования в ChoiceField. Это позволило мне создать произвольный список опций без отдельного обращения к базе данных.

Другой основной частью этого является пользовательский класс Form, который позволяет заполняться полями из BuiltForm. Моя выглядит так:

class BuiltFormGenericForm(forms.Form):
    built_form_fields = {}
    builtform = None
    def addBuiltFormFields(self, fields):
        for field in fields:
            self.fields[field.label] = field.field()
            self.built_form_fields[field.pk] = field
    def is_valid(self):
        # Do validation here.  My code for this is pretty big because of custom fields
        # and calculations that I have to squeeze in.

Объекты BuiltFormField предназначены не для создания через интерфейс администратора, а для создания пользовательского интерфейса с использованием тонны JavaScript, но вы, безусловно, можете представить части модели BuiltFormField в интерфейсе администратора для их обновления.

Надеюсь, это поможет вам разработать модель для ваших форм.

2 голосов
/ 09 февраля 2010

Вы должны использовать определенные модели для этого. Для каждой формы, которая может быть настроена таким образом, должна быть создана новая запись в базе данных. Я думаю, это должно выглядеть так:

class FormSettings(Model):
  form = CharField(..)

class FormAttrib(Model):
  form_settings = ForeignKey(FormSettings)
  field = CharField(..)
  attrib_name=CharField(..)
  attrib_value=CharField(..)

В FormSettings.form вы должны хранить некоторый адрес формы, например, скажем. и когда форма построена (в init ), она должна искать запись в db и использовать атрибуты, которые были описаны для нее.

Вы можете легко создавать записи в БД, если вы используете собственный метакласс для своих форм и заставляете его регистрироваться в базе данных (создавать правильную запись FormSettings), когда создается класс. Это будет сделано один раз, когда процесс начнется, что не должно быть так плохо.

Надеюсь, это немного поможет. Если у вас есть дополнительные вопросы, я буду рад помочь :-) Мне нравятся эти нестандартные приборы django :-) Здесь начинается все самое интересное: -)

EDIT:

ОК, допустим, вы хотите, чтобы у вас была еда приложения и сформировать FavouriteFoodForm с полем food_name. Вы сохраняете в базе данных в таблице formsettings как food.FavouriteFoodForm и добавляете одну настройку атрибута: field = 'food_name', attrib_name = 'required', attribute_value = 'True' (это не идеально, но все же это не так уж плохо ').

Нет, в FavouriteFoddForm вы ищете настройки в базе данных, поэтому вы делаете:

settings = FormSettings.objects.get(form=app_name + self.__class__.name)

и вы перебираете настройки

for setting in settings.formattrib_set():

и здесь вы просто вызываете exec и устанавливаете правильный атрибут:

exec("getattr(self, settings.field)[attrib_name] = %s" % attrib_value)

Это должно установить атрибуты required = True.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...