diff --git a/cadasta/questionnaires/managers.py b/cadasta/questionnaires/managers.py index dd604bc06..9eb4468ec 100644 --- a/cadasta/questionnaires/managers.py +++ b/cadasta/questionnaires/managers.py @@ -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))) @@ -110,12 +111,15 @@ 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 @@ -123,8 +127,8 @@ def create_attrs_schema(project=None, dict=None, content_type=None, errors=[]): 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 ) diff --git a/cadasta/questionnaires/migrations/0006_add_choice_labels.py b/cadasta/questionnaires/migrations/0006_add_choice_labels.py new file mode 100644 index 000000000..bd174eedc --- /dev/null +++ b/cadasta/questionnaires/migrations/0006_add_choice_labels.py @@ -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 + ) + ] diff --git a/cadasta/questionnaires/migrations/0007_add_question_option_index_field.py b/cadasta/questionnaires/migrations/0007_add_question_option_index_field.py new file mode 100644 index 000000000..0a78968d8 --- /dev/null +++ b/cadasta/questionnaires/migrations/0007_add_question_option_index_field.py @@ -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), + ), + ] diff --git a/cadasta/questionnaires/migrations/0008_populate_question_option_index_field.py b/cadasta/questionnaires/migrations/0008_populate_question_option_index_field.py new file mode 100644 index 000000000..09bf7f907 --- /dev/null +++ b/cadasta/questionnaires/migrations/0008_populate_question_option_index_field.py @@ -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 + ) + ] diff --git a/cadasta/questionnaires/migrations/0009_set_question_option_index_field_properties.py b/cadasta/questionnaires/migrations/0009_set_question_option_index_field_properties.py new file mode 100644 index 000000000..829cc4cb9 --- /dev/null +++ b/cadasta/questionnaires/migrations/0009_set_question_option_index_field_properties.py @@ -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(), + ), + ] diff --git a/cadasta/questionnaires/models.py b/cadasta/questionnaires/models.py index 8c1589053..1aa5bac97 100644 --- a/cadasta/questionnaires/models.py +++ b/cadasta/questionnaires/models.py @@ -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() diff --git a/cadasta/questionnaires/tests/factories.py b/cadasta/questionnaires/tests/factories.py index de8a5aa17..c4b1bb04b 100644 --- a/cadasta/questionnaires/tests/factories.py +++ b/cadasta/questionnaires/tests/factories.py @@ -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) diff --git a/requirements/common.txt b/requirements/common.txt index 3b2e2a5c3..82ba75289 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -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