Создание экрана предварительного просмотра в Django

У меня есть Django форма, которая получает текст (который я копирую из Google Classroom: куча комментариев студентов). Я использую эти комментарии для определения посещаемости студента. Я хочу добиться следующего:

  1. Accessing /insertion/ url via GET user receive the page form as a response, to choose the class (class01, class02, etc) and to past the text

  2. When the user clicks on submit in this form (post method), it is redirect to the same /insertion/ url, but now the form is bound to the data submited, and the page shows a preview page (based on a boolean variable I'm passing through context), showing what students are present and what are absent based on the text informed. At that page, a new submit button will be shown below a text like "if everything's ok, hit the ok button".

  3. After click this ok button, a pdf will be generated and the user will be redirected to /files/ url, to see the generated pdf and previous generated 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 - это загадка на данный момент. Я не могу понять, как я могу получить доступ к дорогостоящим вычислениям, которые я сделал в представлении insertion в представлении files. Как я могу это сделать?

Вот решение с использованием session фреймворка.

Мы сохраним вычисления в сессии и получим доступ к этим значениям в другом представлении позже.

Для начала мы просто сохраним идентификаторы (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 для использования . См. PickleSerializer заметки о сериализации сессий.

Вы можете представить первичные ключи как данные формы в скрытых полях. Просто выберите подходящий разделитель, основанный на вашем первичном ключе (например, не разграничивайте дефисом, если вы используете первичный ключ 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>

Затем в представлении вы можете взять PKs из данных формы, а затем запросить.

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)
Вернуться на верх