在 Django 中创建预览屏幕

Create a preview screen in Django

我有一个接收文本的 Django 表单(我从 Google 课堂复制:一堆学生评论)。我使用这些评论来提高学生的出勤率。我想要实现的是:

  1. 通过 GET 访问 /insertion/ url 用户收到页面表单作为响应,选择 class (class01, class02 等) 和过去的文本

  2. 当用户点击此表单中的提交(post 方法)时,它被重定向到相同的 /insertion/ url,但现在表单是绑定到提交的数据,页面显示预览页面(基于我通过上下文传递的布尔变量),根据通知的文本显示学生在场和缺席的情况。在该页面上,一个新的提交按钮将显示在文本下方,例如“如果一切正常,请点击确定按钮”。

  3. 点击这个确定按钮后,会生成一个pdf,用户会被重定向到/files/ url,查看生成的pdf和之前生成的pdf。

views.py

def insertion(request):

    context = {}

    if request.method == 'GET':
        form = AttendanceDataForm()
        context.update({"form": form})

    if request.method == 'POST':
        form = AttendanceDataForm(request.POST)
        context.update({"form": form})
        if form.is_valid():
            lesson = form.cleaned_data['lesson']
            raw_text = form.cleaned_data['raw_text']
            # Get course students
            course_students = md.Student.objects.filter(course_id=lesson.course_id)
            # Get present students based on raw text informed
            present_students = [s for s in course_students if s.full_name in raw_text]
            # Get absent students based on raw text informed
            absent_students = [s for s in course_students if s.full_name not in raw_text]
            context.update({
                "present_students": present_students,
                "absent_students": absent_students,
                "render_preview": True
            })


    context.update({"active_freq": True})

    return render(request, 'core/insertion.html', context)


def files(request):
    context = {}
    if request.method == 'POST':
    
    # How can I access all expensive calculation I did in the previous view?
        

    context.update({"active_gen": True})

    return render(request, "core/files.html", context)

insertion.html

<div class="row">
    <div class="col-12 col-md-6">
        <h3>Informar Frequência</h3>
        {% crispy form %}
    </div>
    <div class="col-12 col-md-6">
        {% if render_preview %}
            <div class="container">
                <div class="row p-4 bg-white rounded mt-4">
                    <div class="col-12 col-sm-6">
                        <h5>Alunos presentes</h5>
                        <ul class="previewer-list">
                            {% for student in present_students %}
                                <li>{{ student.id }} - {{ student.full_name }}</li>
                            {% endfor %}
                        </ul>
                    </div>
                    <div class="col-12 col-sm-6">
                        <h5>Alunos ausentes</h5>
                        <ul class="previewer-list">
                        {% for student in absent_students %}
                            <li>{{ student.id }} - {{ student.full_name }}</li>
                        {% endfor %}
                        </ul>
                    </div>
                </div>
                <p class="mt-3">If everything's ok, hit the OK button</p>
                <form method="post" action="{% url "core:files" %}">
                    {% csrf_token %}
                    <button type="submit" class="btn btn-primary">OK</button>
                </form>
            </div>
        {% endif %}
    </div>
</div>

我可以实现 1 和 2,但 3 现在是个谜。我无法得到的是如何在 files 视图中访问我在 insertion 视图中所做的昂贵计算。我该怎么做?

这是一个使用 session 框架的解决方案。

我们将在会话中保存计算,稍后在另一个视图中访问这些值。

对于初学者,我们将只保存学生的 ID (pk) 而不是学生实例,因为它们 JSON 不可序列化 [见下面的注释] .

def insertion(request):
    # do expensive calucations ...

    present_ids = [s.pk for s in present_students]
    absent_ids = [s.pk for s in absent_students]

    request.session['attendance_data'] = {
        'present_ids': present_ids,
        'absent_ids': absent_ids
    }


def files(request):
    attendance_data = request.session.get('attendance_data')

    if not attendance_data:
        # show error or something else ...
        pass

    present_students = md.Student.objects.filter(
        pk__in=attendance_data['present_ids']
    )
    
    absent_students = md.Student.objects.filter(
        pk__in=attendance_data['absent_ids']
    )

    # generate the pdf ...

注意:如果您愿意,您也可以在会话中保存学生实例,但您必须更改 SESSION_SERIALIZER setting to use the PickleSerializer. See notes about session serialization

您可以将主键作为隐藏字段中的表单数据提交。只需根据您的主键选择合适的分隔符即可(例如,如果您使用 GUID 主键,则不要使用连字符分隔)。

<form method="post" action="{% url "core:files" %}">
    {% csrf_token %}
    <input type="hidden" 
           name="present" 
           value="{% for s in present_students %}{{ s.pk }},{% endfor %}"
    >
    <input type="hidden"
           name="absent" 
           value="{% for s in absent_students %}{{ s.pk }},{% endfor %}"
    >
    <button type="submit" class="btn btn-primary">OK</button>
</form>

然后在视图中,您可以从表单数据中获取视图中的 PK,然后请求。

def files(request):
    context = {}
    if request.method == 'POST':
        present_pks = request.POST.pop('present').split(',')[:-1]
        absent_pks = request.POST.pop('absent').split(',')[:-1]
        # do type conversions if needed
        ...

        # Because we already have the pks separated, we can combine them
        # for the query in order to do just 1 query
        course_students = md.Student.objects.filter(pk__in=present_pks + absent_pks).all()
        absent_students = []
        present_students = []
        for student in course_students:
            if student.pk in absent_pks:
                absent_students.append(student)
            else:
                present_students.append(student)