def get(self, request, *args, **kwargs): self.filter_form = SelectDateForm(request.GET) if request.GET.get('action') == 'CSV': return self.csv() return super().get(request, *args, **kwargs)
def get_filtering(self): """Return filering as a dict for submissions queryset""" self.select_date_form = SelectDateForm(self.request.GET) result = {} if self.select_date_form.is_valid(): date_from = self.select_date_form.cleaned_data.get("date_from") date_to = self.select_date_form.cleaned_data.get("date_to") if date_to: # careful: date_to must be increased by 1 day # as submit_time is a time so will always be greater date_to += datetime.timedelta(days=1) if date_from: result["submit_time__range"] = [date_from, date_to] else: result["submit_time__lte"] = date_to elif date_from: result["submit_time__gte"] = date_from return result
def get_filtering(self): """ Return filering as a dict for submissions queryset """ self.select_date_form = SelectDateForm(self.request.GET) result = dict() if self.select_date_form.is_valid(): date_from = self.select_date_form.cleaned_data.get('date_from') date_to = self.select_date_form.cleaned_data.get('date_to') if date_to: # careful: date_to must be increased by 1 day # as submit_time is a time so will always be greater date_to += datetime.timedelta(days=1) if date_from: result['submit_time__range'] = [date_from, date_to] else: result['submit_time__lte'] = date_to elif date_from: result['submit_time__gte'] = date_from return result
class SubmissionsListView(SpreadsheetExportMixin, SafePaginateListView): """Lists submissions for the provided form page""" template_name = "wagtailforms/index_submissions.html" context_object_name = "submissions" form_page = None ordering = ("-submit_time", ) ordering_csv = ("submit_time", ) # keep legacy CSV ordering orderable_fields = ( "id", "submit_time", ) # used to validate ordering in URL select_date_form = None def dispatch(self, request, *args, **kwargs): """Check permissions and set the form page""" self.form_page = kwargs.get("form_page") if not get_forms_for_user( request.user).filter(pk=self.form_page.id).exists(): raise PermissionDenied self.is_export = self.request.GET.get("export") in self.FORMATS if self.is_export: self.paginate_by = None data_fields = self.form_page.get_data_fields() # Set the export fields and the headings for spreadsheet export self.list_export = [field for field, label in data_fields] self.export_headings = dict(data_fields) return super().dispatch(request, *args, **kwargs) def get_queryset(self): """Return queryset of form submissions with filter and order_by applied""" submission_class = self.form_page.get_submission_class() queryset = submission_class._default_manager.filter( page=self.form_page) filtering = self.get_filtering() if filtering and isinstance(filtering, dict): queryset = queryset.filter(**filtering) ordering = self.get_ordering() if ordering: if isinstance(ordering, str): ordering = (ordering, ) queryset = queryset.order_by(*ordering) return queryset def get_paginate_by(self, queryset): """Get the number of items to paginate by, or ``None`` for no pagination""" if self.is_export: return None return self.paginate_by def get_validated_ordering(self): """Return a dict of field names with ordering labels if ordering is valid""" orderable_fields = self.orderable_fields or () ordering = {} if self.is_export: # Revert to CSV order_by submit_time ascending for backwards compatibility default_ordering = self.ordering_csv or () else: default_ordering = self.ordering or () if isinstance(default_ordering, str): default_ordering = (default_ordering, ) ordering_strs = self.request.GET.getlist("order_by") or list( default_ordering) for order in ordering_strs: try: _, prefix, field_name = order.rpartition("-") if field_name in orderable_fields: ordering[field_name] = ( prefix, "descending" if prefix == "-" else "ascending", ) except (IndexError, ValueError): continue # invalid ordering specified, skip it return ordering def get_ordering(self): """Return the field or fields to use for ordering the queryset""" ordering = self.get_validated_ordering() return [values[0] + name for name, values in ordering.items()] def get_filtering(self): """Return filering as a dict for submissions queryset""" self.select_date_form = SelectDateForm(self.request.GET) result = {} if self.select_date_form.is_valid(): date_from = self.select_date_form.cleaned_data.get("date_from") date_to = self.select_date_form.cleaned_data.get("date_to") if date_to: # careful: date_to must be increased by 1 day # as submit_time is a time so will always be greater date_to += datetime.timedelta(days=1) if date_from: result["submit_time__range"] = [date_from, date_to] else: result["submit_time__lte"] = date_to elif date_from: result["submit_time__gte"] = date_from return result def get_filename(self): """Returns the base filename for the generated spreadsheet data file""" return "{}-export-{}".format( self.form_page.slug, datetime.datetime.today().strftime("%Y-%m-%d")) def render_to_response(self, context, **response_kwargs): if self.is_export: return self.as_spreadsheet(context["submissions"], self.request.GET.get("export")) return super().render_to_response(context, **response_kwargs) def to_row_dict(self, item): """Orders the submission dictionary for spreadsheet writing""" row_dict = OrderedDict( (field, item.get_data().get(field)) for field in self.list_export) return row_dict def get_context_data(self, **kwargs): """Return context for view""" context = super().get_context_data(**kwargs) submissions = context[self.context_object_name] data_fields = self.form_page.get_data_fields() data_rows = [] context["submissions"] = submissions if not self.is_export: # Build data_rows as list of dicts containing model_id and fields for submission in submissions: form_data = submission.get_data() data_row = [] for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ", ".join(val) data_row.append(val) data_rows.append({ "model_id": submission.id, "fields": data_row }) # Build data_headings as list of dicts containing model_id and fields ordering_by_field = self.get_validated_ordering() orderable_fields = self.orderable_fields data_headings = [] for name, label in data_fields: order_label = None if name in orderable_fields: order = ordering_by_field.get(name) if order: order_label = order[1] # 'ascending' or 'descending' else: order_label = "orderable" # not ordered yet but can be data_headings.append({ "name": name, "label": label, "order": order_label, }) context.update({ "form_page": self.form_page, "select_date_form": self.select_date_form, "data_headings": data_headings, "data_rows": data_rows, }) return context
class SubmissionListView(SingleObjectMixin, ListView): paginate_by = 25 page_kwarg = 'p' template_name = 'streamforms/submissions.html' filter_form = None model = BaseForm @property def permission_helper(self): return PermissionHelper(model=self.object.specific_class) def dispatch(self, request, *args, **kwargs): self.object = self.get_object() if not self.permission_helper.user_can_list(self.request.user): raise PermissionDenied return super().dispatch(request, *args, **kwargs) def get_object(self, queryset=None): pk = self.kwargs.get(self.pk_url_kwarg) try: return self.model.objects.get(pk=pk).specific except self.model.DoesNotExist: raise Http404(_("No BaseForm found matching the query")) def get(self, request, *args, **kwargs): self.filter_form = SelectDateForm(request.GET) if request.GET.get('action') == 'CSV': return self.csv() return super().get(request, *args, **kwargs) def csv(self): queryset = self.get_queryset() data_fields = self.object.get_data_fields() data_headings = [smart_str(label) for name, label in data_fields] response = HttpResponse(content_type='text/csv; charset=utf-8') response['Content-Disposition'] = 'attachment;filename=export.csv' writer = csv.writer(response) writer.writerow(data_headings) for s in queryset: data_row = [] form_data = s.get_data() for name, label in data_fields: data_row.append(smart_str(form_data.get(name))) writer.writerow(data_row) return response def get_queryset(self): submission_class = self.object.get_submission_class() self.queryset = submission_class._default_manager.filter(form=self.object) # filter the queryset by the required dates if self.filter_form.is_valid(): date_from = self.filter_form.cleaned_data.get('date_from') date_to = self.filter_form.cleaned_data.get('date_to') if date_from: self.queryset = self.queryset.filter(submit_time__gte=date_from) if date_to: date_to += datetime.timedelta(days=1) self.queryset = self.queryset.filter(submit_time__lte=date_to) return self.queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) data_fields = self.object.get_data_fields() data_headings = [label for name, label in data_fields] # populate data rows from paginator data_rows = [] for s in context['page_obj']: form_data = s.get_data() data_row = [form_data.get(name) for name, label in data_fields] data_rows.append({'model_id': s.id, 'fields': data_row}) context.update({ 'filter_form': self.filter_form, 'data_rows': data_rows, 'data_headings': data_headings, 'has_delete_permission': self.permission_helper.user_can_delete_obj(self.request.user, self.object) }) return context
def list_submissions(request, page_id): # if not get_forms_for_user(request.user).filter(id=page_id).exists(): # raise PermissionDenied form_page = get_object_or_404(Form, id=page_id) #.specific form_submission_class = form_page.get_submission_class() data_fields = form_page.get_data_fields() submissions = form_submission_class.objects.filter( form=form_page).order_by('submit_time') data_headings = [label for name, label in data_fields] select_date_form = SelectDateForm(request.GET) if select_date_form.is_valid(): date_from = select_date_form.cleaned_data.get('date_from') date_to = select_date_form.cleaned_data.get('date_to') # careful: date_to should be increased by 1 day since the submit_time # is a time so it will always be greater if date_to: date_to += datetime.timedelta(days=1) if date_from and date_to: submissions = submissions.filter( submit_time__range=[date_from, date_to]) elif date_from and not date_to: submissions = submissions.filter(submit_time__gte=date_from) elif not date_from and date_to: submissions = submissions.filter(submit_time__lte=date_to) if request.GET.get('action') == 'CSV': # return a CSV instead response = HttpResponse(content_type='text/csv; charset=utf-8') response['Content-Disposition'] = 'attachment;filename=export.csv' # Prevents UnicodeEncodeError for labels with non-ansi symbols data_headings = [smart_str(label) for label in data_headings] writer = csv.writer(response) writer.writerow(data_headings) for s in submissions: data_row = [] form_data = s.get_data() for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(smart_str(val)) writer.writerow(data_row) return response paginator, submissions = paginate(request, submissions) data_rows = [] for s in submissions: form_data = s.get_data() data_row = [] for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(val) data_rows.append({"model_id": s.id, "fields": data_row}) return render( request, 'wagtailforms/index_submissions.html', { 'form_page': form_page, 'select_date_form': select_date_form, 'submissions': submissions, 'data_headings': data_headings, 'data_rows': data_rows })
def list_submissions(request, page_id): if not get_forms_for_user(request.user).filter(id=page_id).exists(): raise PermissionDenied form_page = get_object_or_404(Page, id=page_id).specific form_submission_class = form_page.get_submission_class() data_fields = form_page.get_data_fields() ordering = form_page.get_field_ordering(request.GET.getlist('order_by')) # convert ordering tuples to a list of strings like ['-submit_time'] ordering_strings = [ '%s%s' % ('-' if order_str[1] == 'descending' else '', order_str[0]) for order_str in ordering] if request.GET.get('action') == 'CSV': # Revert to CSV being sorted submit_time ascending for backwards compatibility submissions = form_submission_class.objects.filter(page=form_page).order_by('submit_time') else: submissions = form_submission_class.objects.filter(page=form_page).order_by(*ordering_strings) data_fields_with_ordering = [] for name, label in data_fields: order = None for order_value in [o[1] for o in ordering if o[0] == name]: order = order_value data_fields_with_ordering.append({ "name": name, "label": label, "order": order, }) data_headings = [label for name, label in data_fields] select_date_form = SelectDateForm(request.GET) if select_date_form.is_valid(): date_from = select_date_form.cleaned_data.get('date_from') date_to = select_date_form.cleaned_data.get('date_to') # careful: date_to should be increased by 1 day since the submit_time # is a time so it will always be greater if date_to: date_to += datetime.timedelta(days=1) if date_from and date_to: submissions = submissions.filter(submit_time__range=[date_from, date_to]) elif date_from and not date_to: submissions = submissions.filter(submit_time__gte=date_from) elif not date_from and date_to: submissions = submissions.filter(submit_time__lte=date_to) if request.GET.get('action') == 'CSV': # return a CSV instead response = HttpResponse(content_type='text/csv; charset=utf-8') response['Content-Disposition'] = 'attachment;filename=export.csv' # Prevents UnicodeEncodeError for labels with non-ansi symbols data_headings = [smart_str(label) for label in data_headings] writer = csv.writer(response) writer.writerow(data_headings) for s in submissions: data_row = [] form_data = s.get_data() for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(smart_str(val)) writer.writerow(data_row) return response paginator, submissions = paginate(request, submissions) data_rows = [] for s in submissions: form_data = s.get_data() data_row = [] for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(val) data_rows.append({ "model_id": s.id, "fields": data_row }) return render(request, 'wagtailforms/index_submissions.html', { 'form_page': form_page, 'select_date_form': select_date_form, 'submissions': submissions, 'data_fields_with_ordering': data_fields_with_ordering, 'data_rows': data_rows })
def list_submissions(request, page_id): if not get_forms_for_user(request.user).filter(id=page_id).exists(): raise PermissionDenied form_page = get_object_or_404(Page, id=page_id).specific form_submission_class = form_page.get_submission_class() data_fields = form_page.get_data_fields() ordering = form_page.get_field_ordering(request.GET.getlist('order_by')) # convert ordering tuples to a list of strings like ['-submit_time'] ordering_strings = [ '%s%s' % ('-' if order_str[1] == 'descending' else '', order_str[0]) for order_str in ordering ] if request.GET.get('action') == 'CSV': # Revert to CSV being sorted submit_time ascending for backwards compatibility submissions = form_submission_class.objects.filter( page=form_page).order_by('submit_time') else: submissions = form_submission_class.objects.filter( page=form_page).order_by(*ordering_strings) data_fields_with_ordering = [] for name, label in data_fields: order = None for order_value in [o[1] for o in ordering if o[0] == name]: order = order_value data_fields_with_ordering.append({ "name": name, "label": label, "order": order, }) data_headings = [label for name, label in data_fields] select_date_form = SelectDateForm(request.GET) if select_date_form.is_valid(): date_from = select_date_form.cleaned_data.get('date_from') date_to = select_date_form.cleaned_data.get('date_to') # careful: date_to should be increased by 1 day since the submit_time # is a time so it will always be greater if date_to: date_to += datetime.timedelta(days=1) if date_from and date_to: submissions = submissions.filter( submit_time__range=[date_from, date_to]) elif date_from and not date_to: submissions = submissions.filter(submit_time__gte=date_from) elif not date_from and date_to: submissions = submissions.filter(submit_time__lte=date_to) if request.GET.get('action') == 'CSV': # return a CSV instead response = HttpResponse(content_type='text/csv; charset=utf-8') response['Content-Disposition'] = 'attachment;filename=export.csv' # Prevents UnicodeEncodeError for labels with non-ansi symbols data_headings = [smart_str(label) for label in data_headings] writer = csv.writer(response) writer.writerow(data_headings) for s in submissions: data_row = [] form_data = s.get_data() for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(smart_str(val)) writer.writerow(data_row) return response paginator, submissions = paginate(request, submissions) data_rows = [] for s in submissions: form_data = s.get_data() data_row = [] for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(val) data_rows.append({"model_id": s.id, "fields": data_row}) return render( request, 'wagtailforms/index_submissions.html', { 'form_page': form_page, 'select_date_form': select_date_form, 'submissions': submissions, 'data_fields_with_ordering': data_fields_with_ordering, 'data_rows': data_rows })
class SubmissionsListView(SafePaginateListView): """ Lists submissions for the provided form page """ template_name = 'wagtailforms/index_submissions.html' context_object_name = 'submissions' form_page = None ordering = ('-submit_time',) ordering_csv = ('submit_time',) # keep legacy CSV ordering orderable_fields = ('id', 'submit_time',) # used to validate ordering in URL select_date_form = None def dispatch(self, request, *args, **kwargs): """ Check permissions and set the form page """ self.form_page = kwargs.get('form_page') if not get_forms_for_user(request.user).filter(pk=self.form_page.id).exists(): raise PermissionDenied self.is_csv_export = (self.request.GET.get('action') == 'CSV') if self.is_csv_export: self.paginate_by = None return super().dispatch(request, *args, **kwargs) def get_queryset(self): """ Return queryset of form submissions with filter and order_by applied """ submission_class = self.form_page.get_submission_class() queryset = submission_class._default_manager.filter(page=self.form_page) filtering = self.get_filtering() if filtering and isinstance(filtering, dict): queryset = queryset.filter(**filtering) ordering = self.get_ordering() if ordering: if isinstance(ordering, str): ordering = (ordering,) queryset = queryset.order_by(*ordering) return queryset def get_paginate_by(self, queryset): """ Get the number of items to paginate by, or ``None`` for no pagination """ if self.is_csv_export: return None return self.paginate_by def get_validated_ordering(self): """ Return a dict of field names with ordering labels if ordering is valid """ orderable_fields = self.orderable_fields or () ordering = dict() if self.is_csv_export: # Revert to CSV order_by submit_time ascending for backwards compatibility default_ordering = self.ordering_csv or () else: default_ordering = self.ordering or () if isinstance(default_ordering, str): default_ordering = (default_ordering,) ordering_strs = self.request.GET.getlist('order_by') or list(default_ordering) for order in ordering_strs: try: _, prefix, field_name = order.rpartition('-') if field_name in orderable_fields: ordering[field_name] = ( prefix, 'descending' if prefix == '-' else 'ascending' ) except (IndexError, ValueError): continue # invalid ordering specified, skip it return ordering def get_ordering(self): """ Return the field or fields to use for ordering the queryset """ ordering = self.get_validated_ordering() return [values[0] + name for name, values in ordering.items()] def get_filtering(self): """ Return filering as a dict for submissions queryset """ self.select_date_form = SelectDateForm(self.request.GET) result = dict() if self.select_date_form.is_valid(): date_from = self.select_date_form.cleaned_data.get('date_from') date_to = self.select_date_form.cleaned_data.get('date_to') if date_to: # careful: date_to must be increased by 1 day # as submit_time is a time so will always be greater date_to += datetime.timedelta(days=1) if date_from: result['submit_time__range'] = [date_from, date_to] else: result['submit_time__lte'] = date_to elif date_from: result['submit_time__gte'] = date_from return result def get_csv_filename(self): """ Returns the filename for the generated CSV file """ return 'export-{}.csv'.format( datetime.datetime.today().strftime('%Y-%m-%d') ) def get_csv_response(self, context): """ Returns a CSV response """ filename = self.get_csv_filename() response = HttpResponse(content_type='text/csv; charset=utf-8') response['Content-Disposition'] = 'attachment;filename={}'.format(filename) writer = csv.writer(response) writer.writerow(context['data_headings']) for data_row in context['data_rows']: writer.writerow(data_row) return response def render_to_response(self, context, **response_kwargs): if self.is_csv_export: return self.get_csv_response(context) return super().render_to_response(context, **response_kwargs) def get_context_data(self, **kwargs): """ Return context for view, handle CSV or normal output """ context = super().get_context_data(**kwargs) submissions = context[self.context_object_name] data_fields = self.form_page.get_data_fields() data_rows = [] if self.is_csv_export: # Build data_rows as list of lists containing formatted data values # Using smart_str prevents UnicodeEncodeError for values with non-ansi symbols for submission in submissions: form_data = submission.get_data() data_row = [] for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(smart_str(val)) data_rows.append(data_row) data_headings = [smart_str(label) for name, label in data_fields] else: # Build data_rows as list of dicts containing model_id and fields for submission in submissions: form_data = submission.get_data() data_row = [] for name, label in data_fields: val = form_data.get(name) if isinstance(val, list): val = ', '.join(val) data_row.append(val) data_rows.append({ 'model_id': submission.id, 'fields': data_row }) # Build data_headings as list of dicts containing model_id and fields ordering_by_field = self.get_validated_ordering() orderable_fields = self.orderable_fields data_headings = [] for name, label in data_fields: order_label = None if name in orderable_fields: order = ordering_by_field.get(name) if order: order_label = order[1] # 'ascending' or 'descending' else: order_label = 'orderable' # not ordered yet but can be data_headings.append({ 'name': name, 'label': label, 'order': order_label, }) context.update({ 'form_page': self.form_page, 'select_date_form': self.select_date_form, 'data_headings': data_headings, 'data_rows': data_rows, 'submissions': submissions, }) return context