diff --git a/core/views.py b/core/views.py index 0a22afd1d3424d84a0f586e8b463324a469263ec..9099aa4f3515c4beca51fb4cae2e19e52bc45f01 100644 --- a/core/views.py +++ b/core/views.py @@ -1,4 +1,7 @@ # coding: utf-8 +from django import http + +import unicodecsv as csv class PaginationMixin(object): @@ -22,7 +25,7 @@ class PaginationMixin(object): def get_page_range(self, page): pages = [] - if page.paginator.num_pages != 1: + if page and page.paginator.num_pages != 1: for i in page.paginator.page_range: if page.number - 4 < i < page.number + 4: pages.append(i) @@ -57,3 +60,29 @@ class GridListMixin(object): c = super(GridListMixin, self).get_context_data(**kwargs) c['grid_list'] = True return c + + +class CSVDownloadMixin(object): + def get_paginate_by(self, queryset): + if self.request.GET.get('csv', None) is None: + return super(CSVDownloadMixin, self).get_paginate_by(queryset) + return None + + def render_to_csv_response(self, context, **kwargs): + response = http.HttpResponse(content_type='text/csv') + + writer = csv.writer(response) + for result in self.get_csv_results(context, **kwargs): + writer.writerow(self.get_csv_row(result)) + + response['Content-Disposition'] = 'attachment; filename="%s.csv"' % ( + self.csv_name) + + return response + + def render_to_response(self, context, **kwargs): + if self.request.GET.get('csv', None) is None: + return super(CSVDownloadMixin, self).render_to_response( + context, **kwargs) + + return self.render_to_csv_response(context, **kwargs) diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content index 52bc54725a36530848ee06588fed49687e199c32..2f7442002579e97b8e971a93e2eaaff5e4420be7 100644 --- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content +++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content @@ -84,6 +84,10 @@ <input type='submit' value='Go' /> </form> + <a href='?csv'> + Download data as CSV + + </a> <div class='pagination-block'> diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content index d88608d79697a08612b5737b907f0e0393ce658a..bebce76fbdf9224de743ab35517caaf4478306af 100644 --- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content +++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content @@ -84,6 +84,10 @@ <input type='submit' value='Go' /> </form> + <a href='?search=joly&csv'> + Download data as CSV + + </a> <div class='pagination-block'> diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content index 5f0203ce0e42de6bb045350124117dbe8873fd9a..79b8aed01fae601b79960277d0e3cae4ec9b254f 100644 --- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content +++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content @@ -84,6 +84,10 @@ <input type='submit' value='Go' /> </form> + <a href='?csv'> + Download data as CSV + + </a> <div class='pagination-block'> diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content index 9737215355aeee49b56e07996947ad0af055a124..fb66c4b0e35a89cfacf260da0252b77cc4cfbd76 100644 --- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content +++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content @@ -84,6 +84,10 @@ <input type='submit' value='Go' /> </form> + <a href='?csv'> + Download data as CSV + + </a> <div class='pagination-block'> diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content index 6ee36005948624931aca70a0e1974ed19b467fd6..5513d5c2c57f27c49e446e1b9676ae3132f2e4ef 100644 --- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content +++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content @@ -84,6 +84,10 @@ <input type='submit' value='Go' /> </form> + <a href='?csv'> + Download data as CSV + + </a> <div class='pagination-block'> diff --git a/memopol/views.py b/memopol/views.py index 952ec17b106e44758cbaf5385e0b57447344a424..e668d1d45d615fc626d16e5eb2aa562982a6b3a5 100644 --- a/memopol/views.py +++ b/memopol/views.py @@ -1,7 +1,7 @@ # Project specific "glue" coupling of all apps from django.db import models -from core.views import GridListMixin, PaginationMixin +from core.views import GridListMixin, PaginationMixin, CSVDownloadMixin from representatives import views as representatives_views from representatives.models import Representative from representatives_votes import views as representatives_votes_views @@ -10,8 +10,28 @@ from representatives_positions.forms import PositionForm from representatives_recommendations.models import ScoredVote -class RepresentativeList(PaginationMixin, GridListMixin, - representatives_views.RepresentativeList): +class RepresentativeList( + CSVDownloadMixin, + GridListMixin, + PaginationMixin, + representatives_views.RepresentativeList +): + + csv_name = 'meps.csv' + + def get_csv_results(self, context, **kwargs): + qs = super(RepresentativeList, self).get_queryset() + qs = qs.prefetch_related('email_set') + return [self.add_representative_country_and_main_mandate(r) + for r in qs] + + def get_csv_row(self, obj): + return ( + obj.full_name, + u', '.join([e.email for e in obj.email_set.all()]), + obj.main_mandate.group.abbreviation, + obj.country, + ) queryset = Representative.objects.filter( active=True).select_related('score') diff --git a/setup.py b/setup.py index 788bcfe6d7b38a9920d8a723ce8e64ba1dc44f77..ba922229938b0c3fbb0364a5eead728b53cbb290 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ setup(name='political-memory', 'ijson>=2.2,<2.3', 'lesscpy', 'python-dateutil>=2.4,<2.5', + 'unicodecsv==0.14.1', 'pytz==2015.7', 'django-suit', ], diff --git a/templates/representatives/representative_list.haml b/templates/representatives/representative_list.haml index 4288114df4f021a5cda06d86bc5006f8b2585713..525f375cff9bb0f4fe3a49c5b24c305e05ae153f 100644 --- a/templates/representatives/representative_list.haml +++ b/templates/representatives/representative_list.haml @@ -14,6 +14,9 @@ %input{id:"search", type:"text", name:"search"} %input{type:"submit", value:"Go"} + %a{href:"?{% if request.GET.search %}search={{ request.GET.search }}&{% endif %}csv"} + - trans 'Download data as CSV' + - include 'core/blocks/pagination.html' - block list