fix: update exports for static answerset fields

Resolves #99
This commit is contained in:
James Graham
2021-05-17 18:26:52 +01:00
parent 479ef038d4
commit f37d7c77c4
5 changed files with 57 additions and 68 deletions

View File

@@ -104,7 +104,6 @@ The most likely required settings are: SECRET_KEY, DEBUG, ALLOWED_HOSTS, DATABAS
Google Maps API key to display maps of people's locations Google Maps API key to display maps of people's locations
""" """
import collections
import logging import logging
import logging.config import logging.config
import pathlib import pathlib

View File

@@ -5,6 +5,38 @@ from people import models
from . import base from . import base
def underscore(slug: str) -> str:
"""Replace hyphens with underscores in text."""
return slug.replace('-', '_')
def underscore_dict_keys(dict_: typing.Mapping[str, typing.Any]):
return {underscore(key): value for key, value in dict_.items()}
class AnswerSetSerializer(base.FlattenedModelSerializer):
question_model = None
@property
def column_headers(self) -> typing.List[str]:
headers = super().column_headers
# Add relationship questions to columns
for question in self.question_model.objects.all():
headers.append(underscore(question.slug))
return headers
def to_representation(self, instance: models.question.AnswerSet):
rep = super().to_representation(instance)
rep.update(
underscore_dict_keys(instance.build_question_answers(use_slugs=True, show_all=True))
)
return rep
class PersonSerializer(base.FlattenedModelSerializer): class PersonSerializer(base.FlattenedModelSerializer):
class Meta: class Meta:
model = models.Person model = models.Person
@@ -14,7 +46,8 @@ class PersonSerializer(base.FlattenedModelSerializer):
] ]
class PersonAnswerSetSerializer(base.FlattenedModelSerializer): class PersonAnswerSetSerializer(AnswerSetSerializer):
question_model = models.PersonQuestion
person = PersonSerializer() person = PersonSerializer()
class Meta: class Meta:
@@ -24,38 +57,10 @@ class PersonAnswerSetSerializer(base.FlattenedModelSerializer):
'person', 'person',
'timestamp', 'timestamp',
'replaced_timestamp', 'replaced_timestamp',
'nationality',
'country_of_residence',
'organisation',
'organisation_started_date',
'job_title',
'latitude', 'latitude',
'longitude', 'longitude',
] ]
@property
def column_headers(self) -> typing.List[str]:
headers = super().column_headers
# Add questions to columns
for question in models.PersonQuestion.objects.all():
headers.append(underscore(question.slug))
return headers
def to_representation(self, instance):
rep = super().to_representation(instance)
try:
# Add relationship question answers to data
for answer in instance.question_answers.all():
rep[underscore(answer.question.slug)] = underscore(answer.slug)
except AttributeError:
pass
return rep
class RelationshipSerializer(base.FlattenedModelSerializer): class RelationshipSerializer(base.FlattenedModelSerializer):
source = PersonSerializer() source = PersonSerializer()
@@ -70,12 +75,8 @@ class RelationshipSerializer(base.FlattenedModelSerializer):
] ]
def underscore(slug: str) -> str: class RelationshipAnswerSetSerializer(AnswerSetSerializer):
"""Replace hyphens with underscores in text.""" question_model = models.RelationshipQuestion
return slug.replace('-', '_')
class RelationshipAnswerSetSerializer(base.FlattenedModelSerializer):
relationship = RelationshipSerializer() relationship = RelationshipSerializer()
class Meta: class Meta:
@@ -86,26 +87,3 @@ class RelationshipAnswerSetSerializer(base.FlattenedModelSerializer):
'timestamp', 'timestamp',
'replaced_timestamp', 'replaced_timestamp',
] ]
@property
def column_headers(self) -> typing.List[str]:
headers = super().column_headers
# Add relationship questions to columns
for question in models.RelationshipQuestion.objects.all():
headers.append(underscore(question.slug))
return headers
def to_representation(self, instance):
rep = super().to_representation(instance)
try:
# Add relationship question answers to data
for answer in instance.question_answers.all():
rep[underscore(answer.question.slug)] = underscore(answer.slug)
except AttributeError:
pass
return rep

View File

@@ -7,6 +7,10 @@ from django.views.generic import TemplateView
from django.views.generic.list import BaseListView from django.views.generic.list import BaseListView
class QuotedCsv(csv.excel):
quoting = csv.QUOTE_NONNUMERIC
class CsvExportView(LoginRequiredMixin, BaseListView): class CsvExportView(LoginRequiredMixin, BaseListView):
model = None model = None
serializer_class = None serializer_class = None
@@ -18,7 +22,7 @@ class CsvExportView(LoginRequiredMixin, BaseListView):
# Force ordering by PK - though this should be default anyway # Force ordering by PK - though this should be default anyway
serializer = self.serializer_class(self.get_queryset().order_by('pk'), many=True) serializer = self.serializer_class(self.get_queryset().order_by('pk'), many=True)
writer = csv.DictWriter(response, fieldnames=serializer.child.column_headers) writer = csv.DictWriter(response, dialect=QuotedCsv, fieldnames=serializer.child.column_headers)
writer.writeheader() writer.writeheader()
writer.writerows(serializer.data) writer.writerows(serializer.data)

View File

@@ -8,6 +8,7 @@ class PersonExportView(base.CsvExportView):
model = models.person.Person model = models.person.Person
serializer_class = serializers.people.PersonSerializer serializer_class = serializers.people.PersonSerializer
class PersonAnswerSetExportView(base.CsvExportView): class PersonAnswerSetExportView(base.CsvExportView):
model = models.person.PersonAnswerSet model = models.person.PersonAnswerSet
serializer_class = serializers.people.PersonAnswerSetSerializer serializer_class = serializers.people.PersonAnswerSetSerializer

View File

@@ -166,27 +166,34 @@ class AnswerSet(models.Model):
def is_current(self) -> bool: def is_current(self) -> bool:
return self.replaced_timestamp is None return self.replaced_timestamp is None
def build_question_answers(self, show_all: bool = False) -> typing.Dict[str, str]: def build_question_answers(self,
show_all: bool = False,
use_slugs: bool = False) -> typing.Dict[str, str]:
"""Collect answers to dynamic questions and join with commas.""" """Collect answers to dynamic questions and join with commas."""
questions = self.question_model.objects.all() questions = self.question_model.objects.all()
if not show_all: if not show_all:
questions = questions.filter(answer_is_public=True) questions = questions.filter(answer_is_public=True)
question_answers = {} question_answers = {}
try: try:
answerset_answers = list(self.question_answers.order_by().values('text', 'question_id'))
for question in questions: for question in questions:
key = question.slug if use_slugs else question.text
if question.hardcoded_field: if question.hardcoded_field:
answer = getattr(self, question.hardcoded_field) answer = getattr(self, question.hardcoded_field)
if isinstance(answer, list): if isinstance(answer, list):
answer = ', '.join(map(str, answer)) answer = ', '.join(map(str, answer))
question_answers[question.text] = answer
else: else:
answers = self.question_answers.filter( answer = ', '.join(
question=question) answer['text'] for answer in answerset_answers
question_answers[question.text] = ', '.join( if answer['question_id'] == question.id
map(str, answers)) )
question_answers[key] = answer
except AttributeError: except AttributeError:
# No AnswerSet yet # No AnswerSet yet