User Current Filter and export as PDF

Good Morning Everyone

I have a template that has a form filter that allows people to filter the data and it works fine.I added a function to the view so that they could export the data as a PDF. But it does not seem to use the form filter. It just show all records.

When the user pick the filter on the masterscore template. I want to use that for the PDF filter.

Here is the main template that works with the form filter


<!-- templates/matchscores.html -->
{% extends "base.html" %}
{% load static %}




{% block content %}

<style>
  body {
    background-color: lightblue;
  }

  table, th, td {
    
    border: 1px solid black;
    width: 15em;
    table-layout: fixed;
    border-collapse: collapse;
    text-align: center;
    border: black solid 0.1em;
  }
  
  </style>

   <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">

  <a href="{% url 'export_pdf' %}" class="btn btn-info">Export-PDF</a>
  <a class="text-dark text-sm mb-1" href="{% url 'scores' %}">x Clear Filters</a>
  <form method="get">
   
      <div style="display: grid"> 
          {% for field in filter.form %}
              <div id="form-field-{{ forloop.counter0 }}">
                  {{ field.label_tag }}
                  {{ field }}
              </div>
          {% endfor %}
      </div>
      <button type="submit"  class="btn btn-dark mb-3 mt-2">Filter</button>
      
  </form>
  
<table>
  
  <tr>
    <th>Date</th>
    <th>Username</th>
    <th>Score</th>
    <th>Xcount</th>
    <th>Rilfe Type</th>
    <th>Optic Type</th>
    <th>Range Distance</th>
  </tr>
</table>




{% for scores in filter.qs %}
<div class="Scores-entry">
  
  <table> 
  
   
   <td>{{scores.date}}</td> 
   <td>{{scores.username}}</td>
   <td>{{scores.match_score }}</td>
   <td>{{scores.xcount}}</td>
   <td>{{scores.rilfe_type}}</td>
   <td>{{scores.optic_type}}</td>
   <td>{{scores.range_distance}}</td>
   <td>{{scores.dtotal}}</td>
   
  
 
  
  </table>
  



</div>
{% endfor %}
{% endblock content %} 

Here is the template to create the PDF

<!-- templates/matchscores.html -->

{% load static %}




{% block content %}

<style>
h1 {text-align: center;)}
@page{
    size: landscape;
    margin: .5cm .5cm .5cm .5cm;
}
  body {
  }

  table, th, td {

    border: 1px solid black;
    width: 12em;
    table-layout: auto;
    border-collapse: collapse;
    text-align: center;
    border: black solid 0.1em;
  }

  </style>

   <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
<h1/> SCORES</h1>




<table>

  <tr>
    <th>Date</th>
    <th>Username</th>
    <th>Score</th>
    <th>Xcount</th>
    <th>Range Distance</th>
  </tr>
</table>




{% for scores in scores %}
<div class="Scores-entry">

  <table>


   <td>{{scores.date}}</td>
   <td>{{scores.username}}</td>
   <td>{{scores.match_score }}</td>
   <td>{{scores.xcount}}</td>
   <td>{{scores.range_distance}}</td>





  </table>




</div>
{% endfor %}
{% endblock content %} 

Here is the view for both

# scores/views.py
from django.contrib.auth.mixins import LoginRequiredMixin  # new
from django.views.generic import ListView
from django_filters.views import FilterView
from .models import Scores
from .filters import ScoresFilter
from django.core.files.storage import FileSystemStorage
from django.template.loader import render_to_string
from weasyprint import HTML
import tempfile
import datetime
from django.http import HttpResponse
from django import forms



class ScoresListView(LoginRequiredMixin, FilterView):
    model = Scores
    template_name = 'matchscores.html'
    paginate_by = 10
    filterset_class = ScoresFilter


def export_pdf(request):

    If I hard code the filter here it works example 
 


    html_string = render_to_string('pdf-output.html', {'scores': scores})

    html = HTML(string=html_string)
    html.write_pdf(target='/tmp/mypdf.pdf');

    fs = FileSystemStorage('/tmp')
    with fs.open('mypdf.pdf') as pdf:
        response = HttpResponse(pdf, content_type='application/pdf')
        response['Content-Disposition'] = 'attachment; filename="mypdf.pdf"'
        return response

# Create your views here. 

Here i the url

form the main temple for the PDF
<a href="{% url 'export_pdf' %}" class="btn btn-info">Export-PDF</a>

Thank you all for the help. Its fun to learn

Ed

Side note: When using ``` to fence off code, the lines of ``` must be lines by themselves. (I’ve taken the liberty of fixing your post for you.)

Something may have happened with your formatting or editing of the post here?

Is export_pdf a function within ScoresListView, or is it a separate view?

If it is a separate view, I don’t see where it’s getting the data to be exported.

Side note: We don’t need to see the templates. All the work regarding what data is to be shown is done (or should be done) by the view. However, if these are separate views, and so whatever filter is being applied to the ScoresListView does also need to be passed and applied to the export_pdf view.

Ken

Sorry about the ``` I understand now. export_pdf is a function with in ScoreListView

thank you very much

Then please post the complete ScoreListView, along with your URL definitions for it and for export_pdf as referenced by the url tag shown after the code.

Here is the ScoreListView

# scores/views.py
from django.contrib.auth.mixins import LoginRequiredMixin  # new
from django.views.generic import ListView
from django_filters.views import FilterView
from .models import Scores
from .filters import ScoresFilter
from django.core.files.storage import FileSystemStorage
from django.template.loader import render_to_string
from weasyprint import HTML
import tempfile
import datetime
from django.http import HttpResponse
from django import forms



class ScoresListView(LoginRequiredMixin, FilterView):
    model = Scores
    template_name = 'matchscores.html'
    paginate_by = 10
    filterset_class = ScoresFilter


def export_pdf(request):


    "I want this function to use the same filter that was used in masterscore html"

    scores = Scores.objects.filter(date ='20231028')


    html_string = render_to_string('pdf-output.html', {'scores': scores})

    html = HTML(string=html_string)
    html.write_pdf(target='/tmp/mypdf.pdf');

    fs = FileSystemStorage('/tmp')
    with fs.open('mypdf.pdf') as pdf:
        response = HttpResponse(pdf, content_type='application/pdf')
        response['Content-Disposition'] = 'attachment; filename="mypdf.pdf"'
        return response

# Create your views here.

Here are the url definitions for both

 scores/urls.py
from django.urls import path
from .views import ScoresListView, export_pdf

urlpatterns = [
    path("scores", ScoresListView.as_view(), name="scores"),
    path("export_pdf", export_pdf, name="export_pdf"),
]

As you’ve written it and posted here:

This is not an accurate statement. The export_pdf function is not in ScoreListView. It is a separate and independent function. As such, it has no way to know what filters were used with ScoreListView.

So yes, you will need to construct your export_pdf url using the same filter that was supplied to ScoresListView, and implement the filter within export_pdf.

I think this will mean that you will need to override get_context_data to get the raw text of the filter supplied and assign it to a variable in the context. Your template should then render that variable as a query variable as part of the url.

I don’t use django_filters, so I don’t know if they provide any sort of functionality to facilitate that - it’s probably worth going through the docs to see if you can find anything.

Ken

Do you thing I be better off trying to move the code into the ScoresListView Class or write a separate app with its own form

Thank you Again for all the help

Ed

That doesn’t really matter much either way. You just need to ensure that the same filters get passed into whatever view is going to generate the PDF as what got passed into the view to produce the visible page.

Good Morining Ken

I change the view to function. I have the search part working fine. But I can’t figure out how to pass the match_ filter as a variable to the other function. I try serialization. That failed with a json error.

Could someone point in the right direction. Happy to read to figure this out.

Here is the new View and Templates

# Search/filter use to create a filter  Html Page.

from scores.models import Scores
from django.shortcuts import render
from .filters import MatchFilter
from django.http import HttpResponse
from django.core.files.storage import FileSystemStorage
from django.template.loader import render_to_string
from weasyprint import HTML
from django.core import serializers
def search(request):

    match_list = Scores.objects.all()
    match_filter = MatchFilter(request.GET, queryset=match_list)

    return render(request, 'search.html', {'filter': match_filter})
def Export(request):

    scores = Scores.objects.all()

    html_string = render_to_string('pdf-output.html', {'scores': scores})

    html = HTML(string=html_string)
    html.write_pdf(target='/tmp/mypdf.pdf');

    fs = FileSystemStorage('/tmp')
    with fs.open('mypdf.pdf') as pdf:
        response = HttpResponse(pdf, content_type='application/pdf')
        response['Content-Disposition'] = 'attachment; filename="mypdf.pdf"'
        return response

Search template

<!-- templates/matchscores.html -->
{% extends 'base.html' %}
{% load static %}
{% load crispy_forms_tags %}



{% block content %}

<style>
h1 {text-align: center;)}
@page{
    size: landscape;
    margin: .5cm .5cm .5cm .5cm;
}
  body {
    background-color: lightblue;
  }

  table, th, td {

    border: 1px solid black;
    width: 12em;
    table-layout: fixed;
    border-collapse: collapse;
    text-align: center;
    border: black solid 0.1em;
  }

  </style>

   <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
<h1/> SCORES</h1>
<a class="text-dark text-sm mb-1" href="{% url 'search' %}">x Clear Filter</a>
<a class="text-dark text-sm mb-1" href="{% url 'export_pdf' %}">export_pdf</a>


<form method="get">
    {{ filter.form.as_p }}
    <button type="submit">Filter</button>
  </form>




<table>

  <tr>
    <th>Date</th>
    <th>Username</th>
    <th>Score</th>
    <th>Xcount</th>
    <th>Range Distance</th>
  </tr>
</table>




{% for scores in filter.qs %}
<div class="Scores-entry">

  <table>


   <td>{{scores.date}}</td>
   <td>{{scores.username}}</td>
   <td>{{scores.match_score }}</td>
   <td>{{scores.xcount}}</td>
   <td>{{scores.range_distance}}</td>





  </table>




</div>
{% endfor %}
{% endblock content %}

PDF-Output temple

<!-- templates/pdf-output.html -->

{% load static %}




{% block content %}

<style>
h1 {text-align: center;)}
@page{
    size: landscape;
    margin: .5cm .5cm .5cm .5cm;
}
  body {
    background-color: lightblue;
  }

  table, th, td {

    border: 1px solid black;
    width: 12em;
    table-layout: fixed;
    border-collapse: collapse;
    text-align: center;
    border: black solid 0.1em;
  }

  </style>

   <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
<h1/> SCORES</h1>

<table>

  <tr>
    <th>Date</th>
    <th>Username</th>
    <th>Score</th>
    <th>Xcount</th>
    <th>Range Distance</th>
  </tr>
</table>




{% for scores in scores %}
<div class="Scores-entry">

  <table>


   <td>{{scores.date}}</td>
   <td>{{scores.username}}</td>
   <td>{{scores.match_score }}</td>
   <td>{{scores.xcount}}</td>
   <td>{{scores.range_distance}}</td>





  </table>




</div>
{% endfor %}
{% endblock content %}

Thank you for your help
Ed

Look at what you’re getting in as request.GET. (I’m not sure what you would see - maybe add a print in your view to see exactly what you’re getting there.) It’s that data that needs to be turned into a URL parameter and passed into your context to be rendered as part of the URL for the link.