mirror of
https://github.com/Southampton-RSG/breccia-mapper.git
synced 2026-03-03 03:17:07 +00:00
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
@@ -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,10 +22,10 @@ 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)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user