Поле ForeignKey с другим ForeignKey в FormWizard с MultiValueField - PullRequest
1 голос
/ 24 октября 2011

У меня есть модель с ForeignKey к другой модели, которая также имеет ForeignKey.Я рендерил его с помощью мастера форм django (пытаясь поддерживать как можно более старую версию django), который не inlineformset friendly .Я хочу, чтобы пользователь поместил обе модели и дополнительную информацию в мастер форм и перевел ее в правильное значение pk (чтобы дополнительная информация могла зависеть от комбинации). Мне интересно, как лучше всего подойти к этому.

Для дальнейшего уточнения с кодом.У меня есть три модели:

class Subject(models.Model):
   title = models.CharField(...)
   extra_info = models.CharField(...)

class Topic(models.Model):
   title = models.CharField(...)
   extra_info = models.CharField(...)
   subject = models.ForeignKey(Subject)

class AwesomeThing(models.Model):
   title = models.CharField(...)
   topic = models.ForeignKey(Topic)

Теперь я хочу представить пользователю поле topic из AwesomThing в мастере форм в виде четырех полей:

  • Тема
  • Тема дополнительная информация
  • Тема
  • Тема дополнительная информация

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

class SubjectTopicField(MultiValueField):
  widget = SubjectTopicInput # Multiwidget to present four input fields
  hidden_widget = HiddenInput

  def __init__(self, *args, **kwargs):
    fields = (
      CharField(label='Subject'),
      CharField(label='Subject extra information'),
      CharField(label='Topics'),
      CharField(label='Topic extra information'),
        )

    super(SubjectTopicField, self).__init__(fields, *args, **kwargs)

  def compress(self, data_list):
    # If all four fields are present ...
    if data_list and len(data_list) == 4:
      # ... call and return the topic 'pk' value from a custom method that 
      # creates and/or gets the topic based on the subject and topic info
      return get_or_create_topic(data_list[0], data_list[1], # Subject
                                 data_list[2], data_list[3]) # Topic

    return None

Мой метод get_or_create_topic в основном просто ищет, существует ли эта комбинация предмета и темы, и если да, возвращает ее, а если нет, то создает ее.Проблема в том, что это означает, что он должен попадать в базу данных на каждом этапе.Я вижу, что скрытое представление поля этого поля просто содержит список значений (data_list) вместо значения pk темы.Это не оптимально, на мой взгляд.Есть лучший способ сделать это?Я мог бы просто сосредоточиться на том, чтобы заставить это работать с MultiValueField , что я не вижу надлежащего способа сделать это.

1 Ответ

1 голос
/ 25 октября 2011

Я понял это, я думаю.Ответ заключался в использовании подкласса MultiWidget , но не в качестве подкласса MultiValueField.Я просто указываю в поле моей темы SubjectTopicInput, который наследует MultiWidget , а затем, в дополнение к распаковке, я делаю подкласс value_from_datadict, чтобы вернуть pk (я знаю, что могу сделать его красивее, но это именно то, что я сделал, чтобы заставить его работать):

def value_from_datadict(self, data, files, name):
  # Is there just a single value available which we can return?
  single_value = data.get(name, None)
  if single_value: return single_value

  # No single value, let's try to find our topic (or create it)
  super_value = super(SubjectTopicInput, self).value_from_datadict(data, files, name)
  tc = get_or_create_topic(super_value[0], super_value[1],
                           super_value[2], super_value[3])

  if tc: return tc.pk 

  return None

Очень легко, когда вы перестанете копать и спросите, действительно ли яма нужна.

...