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'))