André Carvalho
André Carvalho

Reputation: 171

Create a preview screen in Django

I have a Django form that receives a text (that I copy from Google Classroom: a bunch of student comments). I use these comments to make student's attendance. What I want to achieve is:

  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>

I could get to implement 1 and 2, but 3 is a mistery right now. What I couldn't get is how I can access the expensive calculations I did in insertion view in the files view. How can I do that?

Upvotes: 1

Views: 981

Answers (2)

sytech
sytech

Reputation: 41081

You could submit the primary keys as form data in hidden fields. Just choose an appropriate delimiter based on your primary key (for example, don't delimit with a hyphen if you use a GUID primary key).

<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>

Then in the view you can pick up the PKs in the view from the form data then request.

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)

Upvotes: 0

xyres
xyres

Reputation: 21799

Here's a solution using session framework.

We'll save the calculations in the session and access those values in another view later.

For starters, we'll just save the ids (pk) of the students instead of the student instances because they are not JSON serializable [See note below].

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 ...

Note: If you wish, you can also save the student instances in the session but you'll have to change the SESSION_SERIALIZER setting to use the PickleSerializer. See notes about session serialization.

Upvotes: 2

Related Questions