Files
breccia-mapper/people/models/organisation.py
2021-05-09 13:53:07 +01:00

162 lines
5.1 KiB
Python

import logging
from django.db import models
from django.urls import reverse
from django_countries.fields import CountryField
from .question import AnswerSet, Question, QuestionChoice
logger = logging.getLogger(__name__) # pylint: disable=invalid-name
__all__ = [
'OrganisationQuestion',
'OrganisationQuestionChoice',
'Organisation',
'OrganisationAnswerSet',
]
class OrganisationQuestion(Question):
"""Question which may be asked about a Organisation."""
#: Should answers to this question be displayed on public profiles?
answer_is_public = models.BooleanField(
help_text='Should answers to this question be displayed on profiles?',
default=True,
blank=False,
null=False)
class OrganisationQuestionChoice(QuestionChoice):
"""Allowed answer to a :class:`OrganisationQuestion`."""
#: Question to which this answer belongs
question = models.ForeignKey(OrganisationQuestion,
related_name='answers',
on_delete=models.CASCADE,
blank=False,
null=False)
class Organisation(models.Model):
"""Organisation to which a :class:`Person` belongs."""
class Meta:
ordering = ['name']
name = models.CharField(max_length=255, blank=False, null=False)
def __str__(self) -> str:
# Prefer name as in latest OrganisationAnswerSet
try:
name = self.current_answers.name
except AttributeError:
name = ''
return name or self.name
@property
def current_answers(self) -> 'OrganisationAnswerSet':
return self.answer_sets.last()
def get_absolute_url(self):
return reverse('people:organisation.detail', kwargs={'pk': self.pk})
class OrganisationAnswerSet(AnswerSet):
"""The answers to the organisation questions at a particular point in time."""
question_model = OrganisationQuestion
#: Organisation to which this answer set belongs
organisation = models.ForeignKey(Organisation,
on_delete=models.CASCADE,
related_name='answer_sets',
blank=False,
null=False)
name = models.CharField(max_length=255, blank=True, null=False)
website = models.URLField(max_length=255, blank=True, null=False)
#: Which countries does this organisation operate in?
countries = CountryField(
multiple=True,
blank=True,
null=False,
help_text=(
'Geographical spread - in which countries does this organisation '
'have offices? Select all that apply'))
#: Which country is this organisation based in?
hq_country = CountryField(
blank=True,
null=False,
help_text=(
'In which country does this organisation have its main location?'))
is_partner_organisation = models.BooleanField(default=False,
blank=False,
null=False)
latitude = models.FloatField(blank=True, null=True)
longitude = models.FloatField(blank=True, null=True)
#: Answers to :class:`OrganisationQuestion`s
question_answers = models.ManyToManyField(OrganisationQuestionChoice)
@property
def location_set(self) -> bool:
return self.latitude and self.longitude
def public_answers(self) -> models.QuerySet:
"""Get answers to questions which are public."""
return self.question_answers.filter(question__answer_is_public=True)
def as_dict(self):
"""Get the answers from this set as a dictionary for use in Form.initial."""
exclude_fields = {
'id',
'timestamp',
'replaced_timestamp',
'organisation_id',
'question_answers',
}
def field_value_repr(field):
"""Get the representation of a field's value as required by Form.initial."""
attr_val = getattr(self, field.attname)
# Relation fields need to return PKs
if isinstance(field, models.ManyToManyField):
return [obj.pk for obj in attr_val.all()]
# But foreign key fields are a PK already so no extra work
return attr_val
answers = {
# Foreign key fields have _id at end in model _meta but don't in forms
field.attname.rstrip('_id'): field_value_repr(field)
for field in self._meta.get_fields()
if field.attname not in exclude_fields
}
for answer in self.question_answers.all():
question = answer.question
field_name = f'question_{question.pk}'
if question.is_multiple_choice:
if field_name not in answers:
answers[field_name] = []
answers[field_name].append(answer.pk)
else:
answers[field_name] = answer.pk
return answers
def get_absolute_url(self):
return self.organisation.get_absolute_url()