Skip to content

Commit

Permalink
Questionnaire choice labels
Browse files Browse the repository at this point in the history
- Data migrations
- Question option indexing (including migrations)
- Bump django-jsonattrs version for choice label handling
  • Loading branch information
Ian Ross committed Sep 29, 2016
1 parent 952a0b0 commit 66f3de7
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 5 deletions.
12 changes: 8 additions & 4 deletions cadasta/questionnaires/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ def create_children(children, errors=[], project=None, kwargs={}):

def create_options(options, question, errors=[]):
if options:
for o in options:
for o, idx in zip(options, itertools.count()):
QuestionOption = apps.get_model('questionnaires', 'QuestionOption')
QuestionOption.objects.create(question=question, **o)

QuestionOption.objects.create(question=question, index=idx+1, **o)
else:
errors.append(_("Please provide at least one option for field"
" '{field_name}'".format(field_name=question.name)))
Expand Down Expand Up @@ -110,21 +111,24 @@ def create_attrs_schema(project=None, dict=None, content_type=None, errors=[]):
if c.get('choices'):
field['choices'] = [choice.get('name')
for choice in c.get('choices')]
field['choice_labels'] = [choice.get('label')
for choice in c.get('choices')]
fields.append(field)

for field, index in zip(fields, itertools.count(1)):
long_name = field.get('long_name', field['name'])
attr_type = AttributeType.objects.get(name=field['attr_type'])
choices = field.get('choices', [])
choice_labels = field.get('choice_labels', None)
default = field.get('default', '')
required = field.get('required', False)
omit = True if field.get('omit', '') == 'yes' else False
Attribute.objects.create(
schema=schema_obj,
name=field['name'], long_name=long_name,
attr_type=attr_type, index=index,
choices=choices, default=default,
required=required, omit=omit
choices=choices, choice_labels=choice_labels,
default=default, required=required, omit=omit
)


Expand Down
75 changes: 75 additions & 0 deletions cadasta/questionnaires/migrations/0006_add_choice_labels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2016-09-26 13:07
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations
from django.contrib.contenttypes.models import ContentType

from organization.models import Project
from jsonattrs.models import Schema, AttributeType


def add_schemas(ss, ct, sels):
for take in range(len(sels) + 1):
for s in Schema.objects.filter(content_type=ct,
selectors=sels[0:take]):
ss.add(s)


def add_attribute_choice_labels(apps, schema_editor):
# Empty database? Probably during testing...
if not AttributeType.objects.exists():
return

Questionnaire = apps.get_model('questionnaires', 'Questionnaire')

select_types = [AttributeType.objects.get(name=n)
for n in ['select_one', 'select_multiple']]
processed_schemas = set()
for prj in Project.objects.all():
org = prj.organization

if (prj.current_questionnaire is not None and
prj.current_questionnaire != ''):
quest = Questionnaire.objects.get(pk=prj.current_questionnaire)
selectors = (org.pk, prj.pk, prj.current_questionnaire)
for ct, sels in settings.JSONATTRS_SCHEMA_SELECTORS.items():
app_label, model = ct.split('.')
content_type = ContentType.objects.get(
app_label=app_label, model=model
)
schemas_to_process = set()
if len(sels) > 3:
cls = content_type.model_class()
selfield = cls._meta.get_field(sels[3])
for choice in selfield.choices:
add_schemas(schemas_to_process, content_type,
selectors + (choice[0],))
else:
add_schemas(schemas_to_process, content_type, selectors)
for schema in schemas_to_process:
if schema not in processed_schemas:
processed_schemas.add(schema)
for a in schema.attributes.filter(
attr_type__in=select_types
):
q = quest.questions.get(name=a.name)
opts = {o.name: o.label for o in q.options.all()}
a.choice_labels = [opts[c] for c in a.choices]
a.save()


class Migration(migrations.Migration):

dependencies = [
('questionnaires', '0005_auto_20160912_0720'),
('jsonattrs', '0002_attribute_choice_labels')
]

operations = [
migrations.RunPython(
add_attribute_choice_labels,
reverse_code=migrations.RunPython.noop
)
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2016-09-27 13:39
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('questionnaires', '0006_add_choice_labels'),
]

operations = [
migrations.AddField(
model_name='historicalquestionoption',
name='index',
field=models.IntegerField(default=1, null=True),
),
migrations.AddField(
model_name='questionoption',
name='index',
field=models.IntegerField(default=1, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2016-09-27 13:42
from __future__ import unicode_literals
import itertools

from django.db import migrations

from questionnaires.models import Question


def populate_index_fields(apps, schema_editor):
for question in Question.objects.filter(type__in=['S1', 'SM']):
for opt, idx in zip(question.options.order_by('index'),
itertools.count()):
opt.index = idx + 1
opt.save()


class Migration(migrations.Migration):

dependencies = [
('questionnaires', '0007_add_question_option_index_field'),
]

operations = [
migrations.RunPython(
populate_index_fields,
reverse_code=migrations.RunPython.noop
)
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2016-09-27 14:31
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('questionnaires', '0008_populate_question_option_index_field'),
]

operations = [
migrations.AlterModelOptions(
name='questionoption',
options={'ordering': ('index',)},
),
migrations.AlterField(
model_name='historicalquestionoption',
name='index',
field=models.IntegerField(),
),
migrations.AlterField(
model_name='questionoption',
name='index',
field=models.IntegerField(),
),
]
4 changes: 4 additions & 0 deletions cadasta/questionnaires/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,12 @@ def has_options(self):


class QuestionOption(RandomIDModel):
class Meta:
ordering = ('index',)

name = models.CharField(max_length=100)
label = models.CharField(max_length=200)
index = models.IntegerField(null=False)
question = models.ForeignKey(Question, related_name='options')

history = HistoricalRecords()
1 change: 1 addition & 0 deletions cadasta/questionnaires/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ class Meta:

name = factory.Sequence(lambda n: "question_option_%s" % n)
label = factory.Sequence(lambda n: "Question Option #%s" % n)
index = factory.Sequence(lambda n: n)
question = factory.SubFactory(QuestionFactory)
2 changes: 1 addition & 1 deletion requirements/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ django-buckets==0.1.16
pyxform-cadasta==0.9.22
python-magic==0.4.11
Pillow==3.2.0
django-jsonattrs==0.1.10
django-jsonattrs==0.1.12
openpyxl==2.3.5
pytz==2016.4
shapely==1.5.16
Expand Down

0 comments on commit 66f3de7

Please sign in to comment.