Skip to content

Commit

Permalink
Fix #935: Conditional attributes not exported during download process
Browse files Browse the repository at this point in the history
  • Loading branch information
bohare authored and amplifi committed Feb 8, 2017
1 parent 36f3cc3 commit 3a82a88
Show file tree
Hide file tree
Showing 7 changed files with 490 additions and 215 deletions.
8 changes: 8 additions & 0 deletions cadasta/core/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ def get_model_attributes(self, project, content_type):
attributes_for_models = self.get_attributes(project)
return attributes_for_models[content_type]

def get_conditional_selector(self, content_type):
content_type_to_selectors = self._get_content_types_to_selectors()
selectors = list(content_type_to_selectors[content_type])
if '.' in selectors[-1]:
return None
else:
return selectors[-1]

def _get_content_types_to_selectors(self):
content_type_to_selectors = dict()
for k, v in settings.JSONATTRS_SCHEMA_SELECTORS.items():
Expand Down
53 changes: 22 additions & 31 deletions cadasta/organization/download/base.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,43 @@
from jsonattrs.models import Schema
from collections import OrderedDict
from core.mixins import SchemaSelectorMixin
from django.contrib.contenttypes.models import ContentType


class Exporter():
class Exporter(SchemaSelectorMixin):
def __init__(self, project):
self.project = project
self._schema_attrs = {}

def get_schema_attrs(self, content_type):
content_type_key = '{}.{}'.format(content_type.app_label,
content_type.model)

if content_type_key not in self._schema_attrs.keys():
selectors = [
self.project.organization.id,
self.project.id,
self.project.current_questionnaire
]
schemas = Schema.objects.lookup(
content_type=content_type, selectors=selectors
)

attrs = []
if schemas:
attrs = [
a for s in schemas
for a in s.attributes.all() if not a.omit
]
self._schema_attrs[content_type_key] = attrs

return self._schema_attrs[content_type_key]
label = '{0}.{1}'.format(content_type.app_label, content_type.model)
if self._schema_attrs == {}:
self._schema_attrs = self.get_attributes(self.project)
return self._schema_attrs[label]

def get_values(self, item, model_attrs, schema_attrs):
values = []
values = OrderedDict()
for attr in model_attrs:
if '.' in attr:
attr_items = attr.split('.')
value = None
for a in attr_items:
value = (getattr(item, a)
if not value else getattr(value, a))
values.append(value)
values[attr] = value
else:
values.append(getattr(item, attr))

for attr in schema_attrs:
attr_value = item.attributes.get(attr.name, '')
values[attr] = getattr(item, attr)

content_type = ContentType.objects.get_for_model(item)
conditional_selector = self.get_conditional_selector(content_type)
if conditional_selector:
entity_type = getattr(item, conditional_selector)
attributes = schema_attrs.get(entity_type, {})
else:
attributes = schema_attrs.get('DEFAULT', {})
for key, attr in attributes.items():
attr_value = item.attributes.get(key, '')
if type(attr_value) == list:
attr_value = (', ').join(attr_value)
values.append(attr_value)
values[key] = attr_value

return values
78 changes: 47 additions & 31 deletions cadasta/organization/download/shape.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import os
import csv
from osgeo import ogr, osr
import os
from collections import OrderedDict
from zipfile import ZipFile

from osgeo import ogr, osr

from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.template.loader import render_to_string
Expand All @@ -12,59 +15,72 @@


class ShapeExporter(Exporter):

def write_items(self, filename, queryset, content_type, model_attrs):
schema_attrs = self.get_schema_attrs(content_type)
fields = list(model_attrs) + [a.name for a in schema_attrs]

# build column labels
attr_columns = OrderedDict()
for a in model_attrs:
attr_columns[a] = ''
for _, attrs in schema_attrs.items():
for a in attrs.values():
if a.name not in attr_columns.keys():
attr_columns[a.name] = None

with open(filename, 'w+', newline='') as csvfile:
csvwriter = csv.writer(csvfile)
csvwriter.writerow(fields)
csvwriter.writerow(attr_columns.keys())

for item in queryset:
values = self.get_values(item, model_attrs, schema_attrs)
csvwriter.writerow(values)
data = attr_columns.copy()
data.update(values)
csvwriter.writerow(data.values())

def write_relationships(self, filename):
relationships = self.project.tenure_relationships.all()
if relationships.count() == 0:
return

content_type = ContentType.objects.get(app_label='party',
model='tenurerelationship')
self.write_items(filename,
self.project.tenure_relationships.all(),
content_type,
self.write_items(filename, relationships, content_type,
('id', 'party_id', 'spatial_unit_id',
'tenure_type.label'))
'tenure_type.id', 'tenure_type.label'))

def write_parties(self, filename):
parties = self.project.parties.all()
if parties.count() == 0:
return

content_type = ContentType.objects.get(app_label='party',
model='party')
self.write_items(filename,
self.project.parties.all(),
content_type,
self.write_items(filename, parties, content_type,
('id', 'name', 'type'))

def write_features(self, layers, filename):
spatial_units = self.project.spatial_units.all()
if spatial_units.count() == 0:
return

content_type = ContentType.objects.get(app_label='spatial',
model='spatialunit')
model_attrs = ('id', 'type')
schema_attrs = self.get_schema_attrs(content_type)

with open(filename, 'w+', newline='') as csvfile:
csvwriter = csv.writer(csvfile)
csvwriter.writerow(list(model_attrs) +
[a.name for a in schema_attrs])

for su in self.project.spatial_units.all():
geom = ogr.CreateGeometryFromWkt(su.geometry.wkt)
layer_type = geom.GetGeometryType() - 1
layer = layers[layer_type]

feature = ogr.Feature(layer.GetLayerDefn())
feature.SetGeometry(ogr.CreateGeometryFromWkt(su.geometry.wkt))
feature.SetField('id', su.id)
layer.CreateFeature(feature)
feature.Destroy()

values = self.get_values(su, model_attrs, schema_attrs)
csvwriter.writerow(values)
self.write_items(
filename, spatial_units, content_type, model_attrs)

for su in spatial_units:
geom = ogr.CreateGeometryFromWkt(su.geometry.wkt)
layer_type = geom.GetGeometryType() - 1
layer = layers[layer_type]

feature = ogr.Feature(layer.GetLayerDefn())
feature.SetGeometry(ogr.CreateGeometryFromWkt(su.geometry.wkt))
feature.SetField('id', su.id)
layer.CreateFeature(feature)
feature.Destroy()

def create_datasource(self, dst_dir):
if not os.path.exists(dst_dir):
Expand Down
27 changes: 17 additions & 10 deletions cadasta/organization/download/xls.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,42 @@
import os
from openpyxl import Workbook
from collections import OrderedDict

from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from openpyxl import Workbook

from .base import Exporter


MIME_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'


class XLSExporter(Exporter):

def write_items(self, worksheet, queryset, content_type, model_attrs):
schema_attrs = self.get_schema_attrs(content_type)

# write column labels
worksheet.append(model_attrs + [a.name for a in schema_attrs])
# build column labels
attr_columns = OrderedDict()
for a in model_attrs:
attr_columns[a] = ''
for _, attrs in schema_attrs.items():
for a in attrs.values():
if a.name not in attr_columns.keys():
attr_columns[a.name] = ''
worksheet.append(list(attr_columns.keys()))

# write data
for i, item in enumerate(queryset):
values = self.get_values(item, model_attrs, schema_attrs)
worksheet.append(values)
data = attr_columns.copy()
data.update(values)
worksheet.append(list(data.values()))

def write_locations(self):
locations = self.project.spatial_units.all()
if locations.count() == 0:
return
worksheet = self.workbook.create_sheet(title='locations')

content_type = ContentType.objects.get(app_label='spatial',
model='spatialunit')
self.write_items(worksheet, locations, content_type,
Expand All @@ -37,7 +47,6 @@ def write_parties(self):
if parties.count() == 0:
return
worksheet = self.workbook.create_sheet(title='parties')

content_type = ContentType.objects.get(app_label='party',
model='party')
self.write_items(worksheet, parties, content_type,
Expand All @@ -48,7 +57,6 @@ def write_relationships(self):
if relationships.count() == 0:
return
worksheet = self.workbook.create_sheet(title='relationships')

content_type = ContentType.objects.get(app_label='party',
model='tenurerelationship')
self.write_items(worksheet, relationships, content_type,
Expand All @@ -57,8 +65,7 @@ def write_relationships(self):

def make_download(self, f_name):
path = os.path.join(settings.MEDIA_ROOT, 'temp/{}.xlsx'.format(f_name))
self.workbook = Workbook()
self.workbook.remove_sheet(self.workbook['Sheet'])
self.workbook = Workbook(write_only=True)

self.write_locations()
self.write_parties()
Expand Down
Loading

0 comments on commit 3a82a88

Please sign in to comment.