|
5 | 5 | from django.utils.text import slugify
|
6 | 6 | from django.http import HttpResponse
|
7 | 7 |
|
8 |
| -from django.conf import settings |
9 |
| -if not settings.configured: |
10 |
| - # required to import ValuesQuerySet |
11 |
| - settings.configure() # pragma: no cover |
12 |
| - |
13 |
| -from django.db.models.query import ValuesQuerySet |
14 |
| - |
15 | 8 | from django.utils import six
|
16 | 9 |
|
17 | 10 | """ A simple python package for turning django models into csvs """
|
@@ -74,24 +67,44 @@ def write_csv(queryset, file_obj, **kwargs):
|
74 | 67 |
|
75 | 68 | # the CSV must always be built from a values queryset
|
76 | 69 | # in order to introspect the necessary fields.
|
77 |
| - if isinstance(queryset, ValuesQuerySet): |
| 70 | + # However, repeated calls to values can expose fields that were not |
| 71 | + # present in the original qs. If using `values` as a way to |
| 72 | + # scope field permissions, this is unacceptable. The solution |
| 73 | + # is to make sure values is called *once*. |
| 74 | + |
| 75 | + # perform an string check to avoid a non-existent class in certain |
| 76 | + # versions |
| 77 | + if type(queryset).__name__ == 'ValuesQuerySet': |
78 | 78 | values_qs = queryset
|
79 | 79 | else:
|
80 |
| - values_qs = queryset.values() |
| 80 | + # could be a non-values qs, or could be django 1.9+ |
| 81 | + iterable_class = getattr(queryset, '_iterable_class', object) |
| 82 | + if iterable_class.__name__ == 'ValuesIterable': |
| 83 | + values_qs = queryset |
| 84 | + else: |
| 85 | + values_qs = queryset.values() |
81 | 86 |
|
82 | 87 | try:
|
83 |
| - field_names = values_qs.field_names |
84 |
| - |
| 88 | + field_names = values_qs.query.values_select |
85 | 89 | except AttributeError:
|
86 |
| - # in django1.5, empty querysets trigger |
87 |
| - # this exception, but not django 1.6 |
88 |
| - raise CSVException("Empty queryset provided to exporter.") |
| 90 | + try: |
| 91 | + field_names = values_qs.field_names |
| 92 | + except AttributeError: |
| 93 | + # in django1.5, empty querysets trigger |
| 94 | + # this exception, but not django 1.6 |
| 95 | + raise CSVException("Empty queryset provided to exporter.") |
89 | 96 |
|
90 | 97 | extra_columns = list(values_qs.query.extra_select)
|
91 | 98 | if extra_columns:
|
92 | 99 | field_names += extra_columns
|
93 | 100 |
|
94 |
| - aggregate_columns = list(values_qs.query.aggregate_select) |
| 101 | + try: |
| 102 | + aggregate_columns = list(values_qs.query.annotation_select) |
| 103 | + except AttributeError: |
| 104 | + # this gets a deprecation warning in django 1.9 but is |
| 105 | + # required in django<=1.7 |
| 106 | + aggregate_columns = list(values_qs.query.aggregate_select) |
| 107 | + |
95 | 108 | if aggregate_columns:
|
96 | 109 | field_names += aggregate_columns
|
97 | 110 |
|
|
0 commit comments