使用 Jinja2 Flask 渲染具有可编辑 WTForms FieldList 和不可编辑值的 HTML Table

Render HTML Table with Editable WTForms FieldList and Non-Editable Values Using Jinja2 Flask

我正在使用 Flask 和 Jinja2,我需要创建一个包含 editable 和非 editable 字段的出勤 table。我参考了其他帖子,例如 here and ,这让我想到了这一点。 table 使用 FieldList 成功显示了 editable 字段。但是,我无法呈现非 editable 字段。

table 应该是这样的:

唯一应该编辑的字段table是“考勤代码”和“评论”。不幸的是,我还没有找到将其他字段(class 名称、开始时间、结束时间、名字、姓氏)包含为简单文本字段的方法。

我试过使用 WTForms 的只读属性。虽然这是功能性的,但它会在看起来不吸引人的文本框中显示文本。

下面显示的我最近的尝试定义了一个名为 updateStudentAttendanceForm 的 WTForms class,它继承了另一个名为 class 的字段 attendanceLogClass,其中包括所需字段的实例变量。我将值分配给 routes.py 文件中的 class 形式。 但是,当我在 html 文件中引用这些变量时,它们会导致空白字段。 我使用打印语句来验证变量赋值是否正常工作。我无法弄清楚为什么包含在 html 模板中的变量无法正确显示。

forms.py

class attendanceLogClass:
    def __init__(self):
        self.classAttendanceLogId = int()
        self.className = str()
        self.firstName = str()
        self.lastName = str()
        self.startTime = datetime()
        self.endTime = datetime()

    def __repr__(self):
        return f"attendanceLogClass('{self.classAttendanceLogId}','{self.className}','{self.firstName}','{self.lastName}','{self.startTime}','{self.endTime}')"


class updateStudentAttendanceForm(FlaskForm, attendanceLogClass):
    attendanceCode = RadioField(
        "Attendance Code",
        choices=[("P", "P"), ("T", "T"), ("E", "E"), ("U", "U"), ("Q", "?"),],
    )
    comment = StringField("Comment")
    submit = SubmitField("Submit Attendance")


class updateClassAttendanceForm(FlaskForm):
    title = StringField("title")
    classMembers = FieldList(FormField(updateStudentAttendanceForm))

routes.py

@app.route("/classattendancelog")
def displayClassAttendanceLog():
    classAttendanceForm = updateClassAttendanceForm()
    classAttendanceForm.title.data = "My class"
    for studentAttendance in ClassAttendanceLog.query.all():
        studentAttendanceForm = updateStudentAttendanceForm()
        studentAttendanceForm.className = studentAttendance.ClassSchedule.className
        studentAttendanceForm.classAttendanceLogId = studentAttendance.id
        studentAttendanceForm.className = studentAttendance.ClassSchedule.className
        studentAttendanceForm.startTime = studentAttendance.ClassSchedule.startTime
        studentAttendanceForm.endTime = studentAttendance.ClassSchedule.endTime
        studentAttendanceForm.firstName = (
            studentAttendance.ClassSchedule.Student.firstName
        )
        studentAttendanceForm.lastName = (
            studentAttendance.ClassSchedule.Student.lastName
        )
        studentAttendanceForm.attendanceCode = studentAttendance.attendanceCode
        studentAttendanceForm.comment = studentAttendance.comment
        # The following print statement verified that all of the variables are properly defined based on the values retrieved from the database query
        print(studentAttendanceForm)
        classAttendanceForm.classMembers.append_entry(studentAttendanceForm)

    return render_template(
        "classattendancelog.html",
        title="Class Attendance Log",
        classAttendanceForm=classAttendanceForm,
    )

classattendancelog.html:

{% extends 'layout.html'%}
{% block content %}
<h1> Class Attendance </h1>
<form method="POST" action="" enctype="multipart/form-data">
  {{ classAttendanceForm.hidden_tag() }}
  <table class="table table-sm table-hover">
    <thead class="thead-light">
      <tr>
        <th scope="col">Class Name</th>
        <th scope="col">Start Time</th>
        <th scope="col">End Time</th>
        <th scope="col">First Name</th>
        <th scope="col">Last Name</th>
        <th scope="col">Attendance Code</th>
        <th scope="col">Comment</th>
      </tr>
    </thead>
    <tbody>

      {% for studentAttendanceForm in classAttendanceForm.classMembers %}
      <tr>
        <td> {{ studentAttendanceForm.className }}</td>
        <td> {{ studentAttendanceForm.startTime }}</td>
        <td> {{ studentAttendanceForm.endTime }}</td>
        <td> {{ studentAttendanceForm.firstName }}</td>
        <td> {{ studentAttendanceForm.lastName }} </td>
        <td>
          {% for subfield in studentAttendanceForm.attendanceCode %}
          {{ subfield }}
          {{ subfield.label }}
          {% endfor %}
        </td>
        <td>
          {{ studentAttendanceForm.comment(class="form-control form-control-sm") }}
        </td>
      </tr>
      {% endfor %}
    </tbody>
  </table>

  {% endblock content %}

注意:我还没有编写处理表单响应的代码。

我通过使用 zip 函数同时遍历两个列表解决了这个问题:一个列表包含 FormField 数据,第二个列表包含不可编辑的“固定字段”数据。

为了在 HTML 模板中使用“zip”,我遵循了说明 here 并将这一行添加到我的 init.py

app.jinja_env.globals.update(zip=zip)

更新forms.py(消除了具有固定字段变量的attendanceLogClass):

class updateStudentAttendanceForm(FlaskForm):
    attendanceCode = RadioField(
        "Attendance Code",
        choices=[("P", "P"), ("T", "T"), ("E", "E"), ("U", "U"), ("Q", "?"),],
    )
    comment = StringField("Comment")
    submit = SubmitField("Submit Attendance")


class updateClassAttendanceForm(FlaskForm):
    title = StringField("title")
    classMembers = FieldList(FormField(updateStudentAttendanceForm))

已更新 routes.py(为称为 classAttendanceFixedFields 的固定字段添加了新变量):

@app.route("/classattendancelog")
def displayClassAttendanceLog():
    classAttendanceFixedFields = ClassAttendanceLog.query.all()
    classAttendanceForm = updateClassAttendanceForm()
    classAttendanceForm.title.data = "My class"

    for studentAttendance in ClassAttendanceLog.query.all():
        studentAttendanceForm = updateStudentAttendanceForm()
        studentAttendanceForm.attendanceCode = studentAttendance.attendanceCode
        studentAttendanceForm.comment = studentAttendance.comment
        classAttendanceForm.classMembers.append_entry(studentAttendanceForm)

    return render_template(
        "classattendancelog.html",
        title="Class Attendance Log",
        classAttendanceForm=classAttendanceForm,
        classAttendanceFixedFields=classAttendanceFixedFields,
    )

已更新classattendancelog.html(在 for 循环中加入 zip 函数以同时遍历可编辑字段和固定字段)。

{% extends 'layout.html'%}
{% block content %}
<h1> Class Attendance </h1>
<form method="POST" action="" enctype="multipart/form-data">
  {{ classAttendanceForm.hidden_tag() }}
  <table class="table table-sm table-hover">
    <thead class="thead-light">
      <tr>
        <th scope="col">Class Name</th>
        <th scope="col">Start Time</th>
        <th scope="col">End Time</th>
        <th scope="col">First Name</th>
        <th scope="col">Last Name</th>
        <th scope="col">Attendance Code</th>
        <th scope="col">Comment</th>
      </tr>
    </thead>
    <tbody>

      {% for studentAttendanceForm, studentFixedFields in zip(classAttendanceForm.classMembers, classAttendanceFixedFields) %}
      <tr>
        <td> {{ studentFixedFields.ClassSchedule.className }}</td>
        <td> {{ studentFixedFields.ClassSchedule.startTime.strftime('%-I:%M') }}</td>
        <td> {{ studentFixedFields.ClassSchedule.endTime.strftime('%-I:%M') }}</td>
        <td> {{ studentFixedFields.ClassSchedule.Student.firstName }}</td>
        <td> {{ studentFixedFields.ClassSchedule.Student.lastName }} </td>
        <td>
          {% for subfield in studentAttendanceForm.attendanceCode %}
          {{ subfield }}
          {{ subfield.label }}
          {% endfor %}
        </td>
        <td>
          {{ studentAttendanceForm.comment(class="form-control form-control-sm") }}
        </td>
      </tr>
      {% endfor %}
    </tbody>
  </table>

  {% endblock content %}