import_specimens.py 4.12 KB
Newer Older
1 2
import csv

3 4
from psycopg2.extras import NumericRange

5
from django.core.exceptions import ObjectDoesNotExist
6 7 8
from django.core.management.base import BaseCommand, CommandError
from django.contrib.gis.geos import Point

Nicolas Noé's avatar
Nicolas Noé committed
9
from specimens.models import Person, SpecimenLocation, Specimen, Fixation, Expedition, Station, UNKNOWN_STATION_NAME
10

11
MODELS_TO_TRUNCATE = [Station, Expedition, Fixation, Person, SpecimenLocation, Specimen]
12 13 14 15 16

# TODO: document use of this script:
# - Column name is important, not column order
# - Lat/lon use comma as a separator

Nicolas Noé's avatar
Nicolas Noé committed
17

18 19 20 21 22 23
def get_or_create_station_and_expedition(station_name, expedition_name):
    # Returns a Station object, ready to assign to Specimen.station
    """

    :rtype: Station
    """
Nicolas Noé's avatar
Nicolas Noé committed
24 25
    if station_name == '':
        station_name = UNKNOWN_STATION_NAME
26

27 28 29 30 31 32 33 34 35
    try: # A station already exists for the correct expedition?
        return Station.objects.get(name=station_name, expedition__name=expedition_name)

    except ObjectDoesNotExist:  # New station, let's create it (with expedition if needed):
        expedition, _ = Expedition.objects.get_or_create(name=expedition_name)
        station = Station.objects.create(name=station_name, expedition=expedition)
        return station


36
class Command(BaseCommand):
Nicolas Noé's avatar
Nicolas Noé committed
37
    help = 'Import specimens from a CSV file and attach them to the existing taxonomy.'
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

    def add_arguments(self, parser):
        parser.add_argument('csv_file')

        parser.add_argument(
            '--truncate',
            action='store_true',
            dest='truncate',
            default=False,
            help='Truncate specimens (and related) tables prior to import',
        )

    def handle(self, *args, **options):
        self.stdout.write('Importing data from file...')
        with open(options['csv_file']) as csv_file:
            if options['truncate']:
54 55 56 57
                for model in MODELS_TO_TRUNCATE:
                    self.stdout.write('Truncate model {name} '.format(name=model.__name__), ending='')
                    model.objects.all().delete()
                    self.stdout.write(self.style.SUCCESS('OK'))
58 59 60

            for i, row in enumerate(csv.DictReader(csv_file, delimiter=',')):
                self.stdout.write('Processing row #{i}...'.format(i=i), ending='')
61 62
                specimen = Specimen()

63 64 65
                specimen.specimen_id = row['Specimen_id'].strip()

                self.stdout.write('Specimen ID is {id}...'.format(id=specimen.specimen_id), ending='')
66 67
                specimen.station = get_or_create_station_and_expedition(row['Station'].strip(), row['Expedition'].strip())

68
                # Identifiers
69
                identified_by = row['Identified_by'].strip()
70
                id_first_name, id_last_name = identified_by.split()
71 72
                identifier, _ = Person.objects.get_or_create(first_name=id_first_name, last_name=id_last_name)
                specimen.identified_by = identifier
73 74 75 76 77

                # Specimen locations
                specimen_location, _ = SpecimenLocation.objects.get_or_create(name=row['Specimen_location'])
                specimen.specimen_location = specimen_location

78
                # Coordinates
79 80 81 82 83
                if row['Latitude'] and row['Longitude']:
                    lat = float(row['Latitude'].replace(',','.'))
                    lon = float(row['Longitude'].replace(',','.'))
                    specimen.coords = Point(lon, lat)

84 85 86 87 88
                # Fixation
                fixation = row['Fixation'].strip()
                if fixation:
                    specimen.fixation, _ = Fixation.objects.get_or_create(name=fixation)

89 90
                specimen.comment = row['Comment']

91 92 93 94
                depth = row['Depth'].strip()
                if depth:
                    if '-' in depth: # It's a range
                        d_min, d_max = depth.split('-')
95
                    else:  # Single value
96
                        d_min = d_max = depth
97

98
                    specimen.depth = NumericRange(float(d_min.replace(',','.')), float(d_max.replace(',','.')), bounds='[]')
99 100 101 102 103 104 105 106 107 108 109 110 111

                specimen.scientific_name = row['Scientific_name']
                specimen.save()
                self.stdout.write(self.style.SUCCESS('OK'))