0

我有一个管理处理作业的 Django 应用程序,我正在尝试创建一个用户友好的流程请求表单。基本上,有一个 Process 模型定义了一个流程,并有一个相关的 ProcessInput 模型来定义输入参数。镜像这两个模型以创建流程的“实例”是 ProcessRequest 和 ProcessRequestInputValue 模型。

这里的要求是,对于一个新的 ProcessRequest,必须有一套完整的 ProcessRequestInputValues 匹配所有的 ProcessInputs。目前,我正在使用 inlineformset_factory 创建用于提交流程请求的表单,该表单允许同时输入所有输入值。我还提供了初始数据来预填充输入选项。这是可行的,但用户可以更改输入值类别,因为它是一个 ModelChoiceField。我想“修复”这个值并将其显示为文本,本质上是一个只读文本小部件。

这是相关的代码。一、机型:

class Process(models.Model):
    process_name = models.CharField(unique=True)

class ProcessInput(models.Model):
    process = models.ForeignKey(Process)
    input_name = models.CharField()
    default_value = models.CharField(null=True, blank=True, max_length=1024)

    class Meta:
        unique_together = (('process', 'input_name'),)

class ProcessRequest(models.Model):
    process = models.ForeignKey(Process)
    request_user = models.ForeignKey(User, editable=False)

class ProcessRequestInputValue(models.Model):
    process_request = models.ForeignKey(ProcessRequest)
    process_input = models.ForeignKey(ProcessInput)
    value = models.CharField(null=False, blank=False, max_length=1024)

    class Meta:
        unique_together = (('process_request', 'process_input'),)

表格很简单:

class ProcessRequestForm(ModelForm):
    class Meta:
        model = ProcessRequest
        exclude = ('process', 'request_user')

class ProcessRequestInputValueForm(ModelForm):
    class Meta:
        model = ProcessRequestInputValue
        exclude = ('process_request',)

最后是表单集视图中的代码:

PRInputValueFormSet = inlineformset_factory(
    ProcessRequest,
    ProcessRequestInputValue,
    form=ProcessRequestInputValueForm,
    extra=process.processinput_set.count(),
    can_delete=False,
)

form = ProcessRequestForm(instance=process_request)

initial_data = list()

for process_input in process.processinput_set.all():
    initial_data.append({'process_input': process_input})

formset = PRInputValueFormSet(
    instance=process_request,
    initial=initial_data)

这很有效,它保留了有关表单错误的所有填写信息。但是,就像我在上面所说的那样,表单将流程输入显示为下拉列表,因为它是一个 ModelChoiceField。

例如,假设我们有一个名为“Add Numbers”的进程,并且有 2 个输入“NumberA”和“NumberB”。这是带有表单集的 ProcessRequest 表单的屏幕截图:

在此处输入图像描述

我想基本上将选择显示为值的标签。我尝试了几种方法,但没有找到任何效果很好的方法。有任何想法吗?

4

3 回答 3

1

我为我的 inline_formsets 做的方式是简单地排除您不希望在表单中显示的字段,这里是 process_input 以及 process_request

class ProcessRequestInputValueForm(ModelForm):
    class Meta:
        model = ProcessRequestInputValue
        exclude = ('process_request','process_input')

现在在基础模型(ProcessRequestInputValue)上设置一个属性值来回答您想要的,在您的情况下,我猜是 ProcessInput 上的 Process 对象:

@property
def my_process(self):
    return self.process_input.process

然后在您的模板中,只需从表单循环内部直接调用该一元方法:

<span>Process Input: {{form.instance.my_process}}</span>

它将调用 Process 对象上的 unicode 方法

这避免了必须制作任何复杂的 ReadOnlyWidgets 等。

于 2013-08-23T23:15:10.393 回答
0

好吧,这似乎是一个 hack,但到目前为止我发现的唯一解决方案是创建一个虚拟表单字段来存储标签值。以下是我到目前为止的代码。

我对此并不满意,我很想看到任何其他解决方案。

表格.py:

class ProcessRequestForm(ModelForm):
    class Meta:
        model = ProcessRequest
        exclude = ('process', 'request_user')


class ProcessRequestInputValueForm(ModelForm):
    value_label = forms.CharField(widget=forms.HiddenInput())
    process_input = forms.ModelChoiceField(
        queryset=ProcessInput.objects.all(),
        widget=forms.HiddenInput())

    class Meta:
        model = ProcessRequestInputValue
        exclude = ('process_request',)

视图.py:

def create_process_request(request, process_id):
    process = get_object_or_404(Process, pk=process_id)
    process_request = ProcessRequest(process=process, request_user=request.user)

    PRInputValueFormSet = inlineformset_factory(
        ProcessRequest,
        ProcessRequestInputValue,
        form=ProcessRequestInputValueForm,
        extra=process.processinput_set.count(),
        can_delete=False,
    )

    if request.method == 'POST':
        # validate the form / formset and save
    else:
        form = ProcessRequestForm(instance=process_request)
        initial_data = list()

        for process_input in process.processinput_set.all():
            # note 'value_label' is used for the 'value' field's label
            initial_data.append(
                {
                    'process_input': process_input,
                    'value_label': process_input.input_name
                })

        formset = PRInputValueFormSet(instance=process_request, initial=initial_data)

    return render_to_response(
        'create_process_request.html',
        {
            'process': process,
            'form': form,
            'formset': formset,
        },
        context_instance=RequestContext(request)
    )

模板:

Process: {{ process.process_name }}<br/>

<form action="{% url 'create_process_request' process.id %}" method="post">
  {% csrf_token %}

  {{ form.non_field_errors }}
  {{ formset.management_form }}
  <Inputs: <br/>

    {% for input_form in formset %}
      {% for hidden_field in input_form.hidden_fields %}

        {% if hidden_field.name == 'process_input' %}
          {{ hidden_field.as_hidden }}
        {% elif hidden_field.name == 'value_label' %}

          {# Needed if form submission has errors, else our custom label goes away #}
          {# Could be used to "hack" our custom label on POST %}
          {{ hidden_field.as_hidden }}

          {# Our custom dynamic label #}
          {{ hidden_field.value }}

        {% endif %}
      {% endfor %}

      {{ input_form.value }}

      {% if input_form.value.errors %}
        {{ input_form.value.errors|striptags }}
      {% endif %}

      <hr/>

    {% endfor %}
      <button type="submit">Save</button>
    </div>
  </div>
</form>

还有一个更有用的形式:

在此处输入图像描述

于 2013-08-13T21:05:43.863 回答
0

你试过禁用吗?

some_field = forms.ChoiceField(choices=my_choices, 
                               widget=forms.Select(attrs={'disabled':'disabled'}))
于 2013-08-13T15:42:44.527 回答