-1

I have a filter class defined below. filters.py

class CTAFilter(django_filters.FilterSet):
    id = django_filters.NumberFilter(label="DSID")
    class Meta:
        model = CTA
        fields = ['id', 'EmailID','id','Shift_timing']

Now I want to use this CTAFilter in normal template(table data)view and in download views.

I have observed that It is working fine for normal render view but when I am using it in my download views it is not working and I am getting all model data in the .xls file.

Please find the below questions which I have posted. how to use Django filtered class data to 2 seperate view

I am not able to resolve this problem I have tried to check if I can define it globally so that the filter will work for all views(like RESTAPI).

Is there any way I can make my download view as a child view class of normal render view so that I will use the below code from the parent view(as it is working fine)?

cta_list = CTA.objects.all() cta_filter = CTAFilter(request.GET, queryset=cta_list) allcta = cta_filter.qs

A>Normal View where the filter is working fine.

 def retrievecta_view(request):
        if request.method == 'GET':
            allcta = CTA.objects.all()
            allcta1 = allcta
            allctagen = allcta1.filter(Shift_timing__exact='General')
            allctamor = allcta1.filter(Shift_timing__exact='Morning')
            allctseve = allcta1.filter(Shift_timing__exact='Evening')
            allctatotal = allcta1.filter(Shift_timing__exact='Total')
    
            # For filtering using   'django_filters',
            cta_list = CTA.objects.all()
            cta_filter = CTAFilter(request.GET, queryset=cta_list)
            allcta = cta_filter.qs
    
            paginator = Paginator(allcta, 50)
            page_number = request.GET.get('page')
            try:
                allcts = paginator.page(page_number)
            except PageNotAnInteger:
                allcts = paginator.page(1)
            except EmptyPage:
                allcts = paginator.page(paginator.num_pages)
            return render(request, 'abcd/cta.html', {'allcta': allcta, 'cta_filter': cta_filter, 'allcta1': allcta1,
                                                      'allctagen': allctagen, 'allctamor': allctamor,
                                                      'allctaeve': allctaeve,
                                                      'allctatotal': allctatotal})

b> Download view where I am trying to use the same filter but it is giving me all records.

def exportcts_data(request):
    response = HttpResponse(content_type='application/ms-excel')
    response['Content-Disposition'] = 'attachment; filename="CTA_ShiftTiming.xls"'
    wb = xlwt.Workbook(encoding='utf-8')
    ws = wb.add_sheet('CTS_ShiftChange Data') # this will make a sheet named Users Data
    # Sheet header, first row
    row_num = 0
    font_style = xlwt.XFStyle()
    font_style.font.bold = True
    columns = ['id','idk','Shift_timing','EmailID','Vendor_Company','Project_name','SerialNumber','Reason','last_updated_time']
    for col_num in range(len(columns)):
        ws.write(row_num, col_num, columns[col_num], font_style) # at 0 row 0 column
    # Sheet body, remaining rows
    font_style = xlwt.XFStyle()
    cts_list = CTA.objects.all()
    cts_filter = CTAFilter(request.GET, queryset=cts_list)
    allcts = cts_filter.qs
    rows = allcts.values_list('id', 'idk', 'Shift_timing', 'EmailID', 'Vendor_Company', 'Project_name',
                              'SerialNumber', 'Reason', 'last_updated_time')
    for row in rows:
        row_num += 1
        for col_num in range(len(row)):
            ws.write(row_num, col_num, row[col_num], font_style)
    wb.save(response)
    return response
Shailesh Yadav
  • 301
  • 2
  • 16
  • Hi schilling, No as mention in question if I'll use two separate view then I am not getting filter queryset(getting all records)in download view . Where as it is working in first view where I am rendering table data. – Shailesh Yadav Dec 23 '20 at 13:58

1 Answers1

1

I'm not quite following why you want to have separate view for downloads which ultimately should be rendering the same data as the normal view if they are using the same filter. Maybe it is just my misunderstanding so I'm not sure if this will help you but let's see.

First off let me explain a little background. This is a task management application and in there I have an html page where the person logged in can view all of their completed tasks. (Nice and simple.) However the user may have tasks from many different projects so I have created a dropdown list that allows them to filter by a single project. They may also want to only see a specific period of tasks so I have allowed them to set a date range by providing a start and end date. (Nothing startling or earth shattering here.) Once the parameters are set, the user clicks a search button and the filtered results are displayed. The page also has an Export button which downloads the results of the filtered list to a .xls spreadsheet.

So how do I do this? Well first of all, I am using Django-Tables2 for rendering my tables. I simple predefine the table in tables.py and throw it the data I want from my views and it takes care of everything. Therefore my view code is minimal and very simple and looks like this.

from django_tables2.export.export import TableExport
from .tables import CompletedTable

     def completedlist(request, page='0', name=''):
            #Check to see if we have clicked a button inside the form
            if request.method == 'POST':
                return redirect ('tasks:tasklist')
            else:
                # Pre-filtering of user and Master = True etc is done in the MasterListFilter in filters.py
                # Then we compile the list for Filtering by. 
                f = CompletedListFilter(request.GET, queryset=Task.objects.all(),request=request)
                # Then we apply the complete list to the table, configure it and then render it.
                completedtable = CompletedTable(f.qs)
                rows = len(completedtable.rows)
                if int(page) > 0:
                    RequestConfig(request, paginate={'page': page, 'per_page': 10}).configure(completedtable)
                else:
                    RequestConfig(request, paginate={'page': 1, 'per_page': 10}).configure(completedtable)
                export_format = request.GET.get('_export', None)  
                if TableExport.is_valid_format(export_format):
                    exporter = TableExport(export_format, completedtable)
                    return exporter.response('Completed Tasks.{}'.format(export_format))
                return render (request,'tasks/completedlist.html',{'completedtable': completedtable, 'filter': f, 'rows': rows})

As you can see, every time the user hits either the search or export buttons, I am recompiling the queryset in variable f with the following line:

f = CompletedListFilter(request.GET, queryset=Task.objects.all(),request=request)

I have predefined the .xls format in the html page with this code:

<button class="btn btn-primary btn-xs" name="_export" value="xls" type="submit">Export</button>

So then I can test to see if the user clicked the Export button or not by getting the value of _export from the request like this:

export_format = request.GET.get('_export', None)

If the user did not click the export button, export_format will default to none. If they did, it will be .xls as defined in the html. Then I simply either export the data in line with the filters set by the user or I render the page with the same filtered list of data like this:

if TableExport.is_valid_format(export_format):
      exporter = TableExport(export_format, completedtable)
      return exporter.response('Completed Tasks.{}'.format(export_format))
return render (request,'tasks/completedlist.html',{'completedtable': completedtable, 'filter': f, 'rows': rows})
 

So there you have it. As you say your filter is working for the normal view I have not detailed my filter as that would seem to be unnecessary.

Maybe this solution is too simplistic for your requirements and yes, before I get shot down by other developers, there are several limitations, such as 'What if the user wants to use something other than .xls?' or 'What if they want to export more than one Project at a time?' Like everything, there is always room for improvement but when I'm bashing my head with an issue, I often find it helps to strip things back to basics and see what comes from that.

cander
  • 279
  • 6
  • 14