1

我有一个带有外键的模型到另一个也有外键的模型。我正在使用不适合 inlineformset的 django 表单向导(尝试支持尽可能旧的 django 版本)渲染它。我希望用户在表单向导中输入模型和额外信息并将其转换为正确的 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)

现在,我想在表单向导中将AwesomThing的主题字段作为四个字段呈现给用户:

  • 主题
  • 主题额外信息
  • 话题
  • 主题额外信息

我正在使用MultiValueFieldMultiWidget来完成此操作,但我不确定保留值并在表单向导中的步骤之间传输它的最佳方法。我能够做到这一点,但我担心我的方法过于频繁地访问数据库。这是我目前的做法:

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一起工作,我看不到这样做的正确方法。

4

1 回答 1

1

我想通了。答案是使用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

当你停止挖掘并质疑这个洞是否真的有必要时,真的很容易。

于 2011-10-25T08:51:37.073 回答