【问题标题】:Create a preview screen in Django在 Django 中创建预览屏幕
【发布时间】:2021-12-06 19:28:37
【问题描述】:

我有一个接收文本的 Django 表单(我从 Google Classroom 复制:一堆学生 cmets)。我用这些cmets来做学生的出勤率。我想要实现的是:

  1. 通过 GET 用户访问/insertion/ url 接收页面表单作为响应,选择类(class01、class02 等)并粘贴文本

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

  3. 点击这个ok按钮后,会生成一个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)

插入.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 视图中所做的昂贵计算。我该怎么做?

【问题讨论】:

  • 您可以使用FormPreviewdjango-formtools - docs 实现此目的

标签: python django django-views django-templates frontend


【解决方案1】:

这是使用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 以使用 PickleSerializer。见notes about session serialization

【讨论】:

    【解决方案2】:

    您可以在隐藏字段中将主键作为表单数据提交。只需根据您的主键选择适当的分隔符(例如,如果您使用 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-18
      • 2012-09-01
      • 1970-01-01
      相关资源
      最近更新 更多