Skip to content

Commit f10a070

Browse files
committed
Add in the ability to export specific imports
These are not async so will block, but given that this is an admin only feature I think that should be okay.
1 parent ed196cb commit f10a070

File tree

5 files changed

+163
-32
lines changed

5 files changed

+163
-32
lines changed

importer/models.py

+32-32
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,36 @@ class TreeImportRow(GenericImportRow):
809809
WATCH=2
810810
VERIFIED=4
811811

812+
PLOT_MAP = {
813+
'geometry': fields.trees.POINT,
814+
'width': fields.trees.PLOT_WIDTH,
815+
'length': fields.trees.PLOT_LENGTH,
816+
'type': fields.trees.PLOT_TYPE,
817+
'readonly': fields.trees.READ_ONLY,
818+
'sidewalk_damage': fields.trees.SIDEWALK,
819+
'powerline_conflict_potential': fields.trees.POWERLINE_CONFLICT,
820+
'owner_orig_id': fields.trees.ORIG_ID_NUMBER,
821+
'owner_additional_id': fields.trees.DATA_SOURCE,
822+
'owner_additional_properties': fields.trees.NOTES
823+
}
824+
825+
TREE_MAP = {
826+
'tree_owner': fields.trees.OWNER,
827+
'steward_name': fields.trees.STEWARD,
828+
'dbh': fields.trees.DIAMETER,
829+
'height': fields.trees.TREE_HEIGHT,
830+
'canopy_height': fields.trees.CANOPY_HEIGHT,
831+
'species': fields.trees.SPECIES_OBJECT,
832+
'sponsor': fields.trees.SPONSOR,
833+
'date_planted': fields.trees.DATE_PLANTED,
834+
'readonly': fields.trees.READ_ONLY,
835+
'projects': fields.trees.LOCAL_PROJECTS,
836+
'condition': fields.trees.TREE_CONDITION,
837+
'canopy_condition': fields.trees.CANOPY_CONDITION,
838+
'url': fields.trees.URL,
839+
'pests': fields.trees.PESTS
840+
}
841+
812842
# plot that was created from this row
813843
plot = models.ForeignKey(Plot, null=True, blank=True)
814844

@@ -883,37 +913,7 @@ def commit_row(self):
883913

884914
data_owner = self.import_event.owner
885915

886-
plot_map = {
887-
'geometry': fields.trees.POINT,
888-
'width': fields.trees.PLOT_WIDTH,
889-
'length': fields.trees.PLOT_LENGTH,
890-
'type': fields.trees.PLOT_TYPE,
891-
'readonly': fields.trees.READ_ONLY,
892-
'sidewalk_damage': fields.trees.SIDEWALK,
893-
'powerline_conflict_potential': fields.trees.POWERLINE_CONFLICT,
894-
'owner_orig_id': fields.trees.ORIG_ID_NUMBER,
895-
'owner_additional_id': fields.trees.DATA_SOURCE,
896-
'owner_additional_properties': fields.trees.NOTES
897-
}
898-
899-
tree_map = {
900-
'tree_owner': fields.trees.OWNER,
901-
'steward_name': fields.trees.STEWARD,
902-
'dbh': fields.trees.DIAMETER,
903-
'height': fields.trees.TREE_HEIGHT,
904-
'canopy_height': fields.trees.CANOPY_HEIGHT,
905-
'species': fields.trees.SPECIES_OBJECT,
906-
'sponsor': fields.trees.SPONSOR,
907-
'date_planted': fields.trees.DATE_PLANTED,
908-
'readonly': fields.trees.READ_ONLY,
909-
'projects': fields.trees.LOCAL_PROJECTS,
910-
'condition': fields.trees.TREE_CONDITION,
911-
'canopy_condition': fields.trees.CANOPY_CONDITION,
912-
'url': fields.trees.URL,
913-
'pests': fields.trees.PESTS
914-
}
915-
916-
for modelkey, importdatakey in plot_map.iteritems():
916+
for modelkey, importdatakey in TreeImportRow.PLOT_MAP.iteritems():
917917
importdata = data.get(importdatakey, None)
918918

919919
if importdata:
@@ -925,7 +925,7 @@ def commit_row(self):
925925
plot.import_event = base_treemap_import_event
926926
plot.save()
927927

928-
for modelkey, importdatakey in tree_map.iteritems():
928+
for modelkey, importdatakey in TreeImportRow.TREE_MAP.iteritems():
929929
importdata = data.get(importdatakey, None)
930930

931931
if importdata:

importer/urls.py

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
(r'^status/species/(?P<import_event_id>\d+)$', 'show_species_import_status'),
1111
(r'^update/(?P<import_event_row_id>\d+)$', 'update_row'),
1212

13+
(r'^export/species/all', 'export_all_species'),
14+
(r'^export/species/(?P<import_event_id>\d+)$', 'export_single_species_import'),
15+
(r'^export/tree/(?P<import_event_id>\d+)$', 'export_single_tree_import'),
16+
1317
# API
1418
(r'^api/(?P<import_type>[a-z]+)/(?P<import_event_id>\d+)/results/(?P<subtype>[a-zA-Z]+)$',
1519
'results'),

importer/views.py

+118
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import csv
22
import json
3+
from StringIO import StringIO
34
from datetime import datetime
45

56
from django.db import transaction
@@ -421,6 +422,123 @@ def process_csv(request, fileconstructor, **kwargs):
421422

422423
return ie.pk
423424

425+
@login_required
426+
def export_all_species(request):
427+
io = StringIO()
428+
429+
# Maps [attr on species model] -> field name
430+
fieldmap = SpeciesImportRow.SPECIES_MAP
431+
fields = fieldmap.values()
432+
433+
writer = csv.DictWriter(io, fields)
434+
writer.writeheader()
435+
436+
for s in Species.objects.all():
437+
obj = {v: getattr(s, k) for (k, v) in fieldmap.iteritems()}
438+
writer.writerow(obj)
439+
440+
response = HttpResponse(io.getvalue(), mimetype='text/csv')
441+
response['Content-Disposition'] = 'attachment; filename=species.csv'
442+
443+
return response
444+
445+
@login_required
446+
def export_single_species_import(request, import_event_id):
447+
fieldmap = SpeciesImportRow.SPECIES_MAP
448+
fields = fieldmap.values()
449+
450+
ie = SpeciesImportEvent.objects.get(pk=import_event_id)
451+
452+
io = StringIO()
453+
454+
writer = csv.DictWriter(io, fields)
455+
writer.writeheader()
456+
457+
for r in ie.rows():
458+
if r.species:
459+
obj = {v: getattr(r.species, k) for (k, v) in fieldmap.iteritems()}
460+
else:
461+
obj = lowerkeys(json.loads(r.data))
462+
463+
writer.writerow(obj)
464+
465+
response = HttpResponse(io.getvalue(), mimetype='text/csv')
466+
response['Content-Disposition'] = 'attachment; filename=species.csv'
467+
468+
return response
469+
470+
@login_required
471+
def export_single_tree_import(request, import_event_id):
472+
plotmap = TreeImportRow.PLOT_MAP
473+
treemap = TreeImportRow.TREE_MAP
474+
475+
all_fields = list(fields.trees.ALL)
476+
477+
ie = TreeImportEvent.objects.get(pk=import_event_id)
478+
479+
io = StringIO()
480+
481+
writer = csv.DictWriter(io, all_fields)
482+
writer.writeheader()
483+
484+
for r in ie.rows():
485+
if r.plot:
486+
obj = {}
487+
obj[fields.trees.POINT_X] = r.plot.geometry.x
488+
obj[fields.trees.POINT_Y] = r.plot.geometry.y
489+
490+
obj[fields.trees.ADDRESS] = r.plot.address_street
491+
obj[fields.trees.PLOT_WIDTH] = r.plot.width
492+
obj[fields.trees.PLOT_LENGTH] = r.plot.length
493+
obj[fields.trees.READ_ONLY] = r.plot.readonly
494+
obj[fields.trees.OPENTREEMAP_ID_NUMBER] = r.plot.pk
495+
obj[fields.trees.ORIG_ID_NUMBER] = r.plot.owner_orig_id
496+
obj[fields.trees.DATA_SOURCE] = r.plot.owner_additional_id
497+
obj[fields.trees.NOTES] = r.plot.owner_additional_properties
498+
obj[fields.trees.SIDEWALK] = r.plot.sidewalk_damage
499+
obj[fields.trees.POWERLINE_CONFLICT] = r.plot.powerline_conflict_potential
500+
obj[fields.trees.PLOT_TYPE] = r.plot.type
501+
502+
tree = r.plot.current_tree()
503+
504+
obj[fields.trees.TREE_PRESENT] = tree is not None
505+
506+
if tree:
507+
species = tree.species
508+
509+
if species:
510+
obj[fields.trees.GENUS] = species.genus
511+
obj[fields.trees.SPECIES] = species.species
512+
obj[fields.trees.CULTIVAR] = species.cultivar_name
513+
obj[fields.trees.OTHER_PART_OF_NAME] = species.other_part_of_name
514+
515+
516+
obj[fields.trees.DIAMETER] = tree.dbh
517+
obj[fields.trees.TREE_HEIGHT] = tree.height
518+
obj[fields.trees.CANOPY_HEIGHT] = tree.canopy_height
519+
obj[fields.trees.DATE_PLANTED] = tree.date_planted
520+
obj[fields.trees.OWNER] = tree.tree_owner
521+
obj[fields.trees.SPONSOR] = tree.sponsor
522+
obj[fields.trees.STEWARD] = tree.steward_name
523+
obj[fields.trees.URL] = tree.url
524+
525+
obj[fields.trees.TREE_CONDITION] = tree.condition
526+
obj[fields.trees.CANOPY_CONDITION] = tree.canopy_condition
527+
obj[fields.trees.PESTS] = tree.pests
528+
obj[fields.trees.LOCAL_PROJECTS] = tree.projects
529+
530+
else:
531+
obj = lowerkeys(json.loads(r.data))
532+
533+
writer.writerow(obj)
534+
535+
response = HttpResponse(io.getvalue(), mimetype='text/csv')
536+
response['Content-Disposition'] = 'attachment; filename=trees.csv'
537+
538+
return response
539+
540+
541+
424542
def process_commit(request, import_id):
425543
ie = TreeImportEvent.objects.get(pk=import_id)
426544

templates/importer/list.html

+5
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ <h2>Active Species Imports</h2>
8383
<h2>Finished Species Imports</h2>
8484
{% include 'importer/partials/import_table.html' with things=species_finished id="finishedspecies" link="species" %}
8585
</div>
86+
<h3>
87+
<a href="{{ SITE_ROOT }}importer/export/species/all">
88+
Export All Species
89+
</a>
90+
</h3>
8691
</div>
8792

8893
{% endblock %}

templates/importer/partials/active_row.html

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
{% if ie.status == 3 or ie.status == 5 or ie.status == 6 %}
1818
<td>{{ ie.rows.count }}</td>
1919
<td>
20+
<a href="{{ SITE_ROOT }}importer/export/{{ link }}/{{ ie.pk }}">
21+
Export
22+
</a>
23+
|
2024
<a href="{{ SITE_ROOT }}importer/status/{{ link }}/{{ ie.pk}}">
2125
View
2226
</a>

0 commit comments

Comments
 (0)