Поле выбора динамической модели в наборе форм django с использованием нескольких элементов выбора - PullRequest
2 голосов
/ 16 января 2011

Я разместил этот вопрос в списке пользователей django, но пока не получил ответа.

У меня есть модели, которые выглядят примерно так:

class ProductGroup(models.Model):
     name = models.CharField(max_length=10, primary_key=True)
     def __unicode__(self): return self.name

class ProductRun(models.Model):
     date = models.DateField(primary_key=True)
     def __unicode__(self): return self.date.isoformat()

class CatalogItem(models.Model):
     cid     = models.CharField(max_length=25, primary_key=True)
     group   = models.ForeignKey(ProductGroup)
     run     = models.ForeignKey(ProductRun)
     pnumber = models.IntegerField()
     def __unicode__(self): return self.cid
     class Meta:
         unique_together = ('group', 'run', 'pnumber')

class Transaction(models.Model):
     timestamp   = models.DateTimeField()
     user        = models.ForeignKey(User)
     item        = models.ForeignKey(CatalogItem)
     quantity    = models.IntegerField()
     price       = models.FloatField()

Допустим,в любой момент времени существует около 10 групп товаров и 10-20 соответствующих продуктов.Каждая группа имеет 20-200 различных номеров продуктов (pnumber), поэтому существует не менее нескольких тысяч CatalogItems.

Я работаю над наборами форм для модели транзакций.Вместо одного меню выбора с несколькими тысячами CatalogItems для поля ForeignKey я хочу заменить три раскрывающихся меню для group, run и pnumber, которые однозначно идентифицируют CatalogItem.Я также хотел бы ограничить варианты во вторых двух раскрывающихся списках теми прогонами и числами, которые доступны для выбранной в данный момент группы продуктов (я могу обновить их через AJAX, если пользователь меняет группу продуктов, но важно, чтобыначальная загрузка страницы, как описано, не полагаясь на AJAX).

Какой лучший способ сделать это?

В качестве отправной точки, вот что я пытался / рассматривал до сих пор:

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

Мой второй подход состоял в том, чтобы создать новое поле, которое наследует и MultiValueField и ModelChoiceField, исоответствующий подкласс MultiWidget.Это похоже на правильный подход.Как сказал Малкольм Трединник в дискуссии пользователей django , «ум» поля лежит в классе Field.

Проблема в том, когда и гдеполучить списки вариантов из БД.Код, который у меня есть, теперь делает это в __init__ поля, но это означает, что я должен знать, с какой ProductGroup я имею дело, прежде чем я смогу даже определить класс Form, поскольку мне приходится создавать экземпляр поля при определении формы.Таким образом, у меня есть фабричная функция, которую я вызываю в последнюю минуту с моей точки зрения - после того, как я знаю, какие у меня есть CatalogItem и в какую группу продуктов они входят - для создания классов form / formset и создания их экземпляров.Это работает, но мне интересно, есть ли лучший способ.В конце концов, поле должно быть в состоянии определить правильный выбор намного позже, как только оно узнает его текущее значение.

Другая проблема состоит в том, что моя реализация ограничивает весь набор форм транзакциями, относящимися к (CatalogItems from) одногоProductGroup.

Третья возможность, которую я развлекаю, - поместить все это в класс Widget.Как только у меня появится экземпляр связанной модели, или cid, или какой-либо другой виджет, я могу получить группу ProductGroup и создать выпадающие списки.Это решило бы проблемы с моим вторым подходом, но не похоже на правильный подход.

Ответы [ 2 ]

4 голосов
/ 27 августа 2014

Один из способов установки выбора полей формы в наборе форм - в формах init и перезаписи self.fields ['field_name']. Choices, но поскольку требуется более динамичный подход, здесь это то, что работает в представлении:

from django.forms.models import modelformset_factory
user_choices = [(1, 'something'), (2, 'something_else')]  # some basic choices
PurchaserChoiceFormSet = modelformset_factory(PurchaserChoice, form=PurchaserChoiceForm, extra=5, max_num=5)
my_formset = PurchaserChoiceFormSet(self.request.POST or None, queryset=worksheet_choices)

# and now for the magical for loop
for choice_form in my_formset:
    choice_form.fields['model'].choices = user_choices

Я не смог найти ответ на этот вопрос, но попробовал его, и он работает в Django 1.6.5. Я понял это, так как формы и циклы for, кажется, отлично сочетаются:)

0 голосов
/ 06 ноября 2011

Я закончил придерживаться второго подхода, но теперь я убежден, что это был Короткий путь, который был очень длинным.Мне пришлось немного покопаться во внутренностях ModelForm и FormField, и IMO сложность перевешивает минимальные преимущества.

То, что я написал в вопросе о первом подходе: «Это просто и довольно просто», должно иметьбыл наводкой.

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