Parsing fields in django-import-export before importing
Asked Answered
B

3

11

I am using django-import-export package to expect a csv file containing a location's name and its longitude and latitude.

I want to parse the longitude and latitude field from the csv to convert them into django.contrib.gis.geos.Point object so that I can input it to my Location model's geom field.

# models.py
from django.contrib.gis.db import models
class Location(models.Model):
    name = models.CharField(max_length=200)
    geom = models.PointField(null=True, blank=True)

    def __str__(self):
        return self.name

# admin.py
from .models import Location
from import_export import resources
from import_export.admin import ImportExportModelAdmin

class LocationResource(resources.ModelResource):
    geom = Field()
    latitude = Field()
    longitude = Field()

    class Meta:
        model = Location
        fields = ('id','name', 'latitude', 'longitude')
        exclude = ('geom')
        export_order = ('id', 'name', 'latitude', 'longitude')

    def dehydrate_geom(self, data):
        return Point(data.longitude, data.longitude)

class LocationAdmin(ImportExportModelAdmin):
    resource_class = LocationResource

admin.site.register(Location, LocationAdmin)

This is how far I got but to no success. Must have:

Location(name='name', geom=Point(longitude, latitude))

CSV file: locations.csv

id,name,longitude,latitude
1,Naga,120.18,18.20

UPDATE 1 Tried using hydrate_<field_name> but with no success.

class ProjectActivityResource(resources.ModelResource):
    latitude = Field(attribute='latitude', column_name='latitude')
    longitude = Field(attribute='longitude', column_name='longitude')

    class Meta:
        model = ProjectActivity
        fields = ('id', 'project_site', 'name', 'latitude',
                        'longitude', 'date_updated')
        exclude = ('geom')
        export_order = ('id', 'project_site', 'name', 'latitude',
                        'longitude', 'date_updated')

    def hydrate_geom(self, project_activity):
        print(project_activity)
        return Point(float(project_activity.longitude), float(project_activity.longitude))
Berbera answered 27/7, 2019 at 14:45 Comment(0)
B
15

It was resolved when I used before_save_instance(self, instance, using_transactions, dry_run)

The function can modify the object before passing it to the model.

class ProjectActivityResource(resources.ModelResource):
    latitude = Field(attribute='latitude', column_name='latitude')
    longitude = Field(attribute='longitude', column_name='longitude')

    class Meta:
        model = ProjectActivity
        fields = ('id', 'project_site', 'name', 'latitude',
                        'longitude', 'date_updated')
        exclude = ('geom')
        export_order = ('id', 'project_site', 'name', 'latitude',
                        'longitude', 'date_updated')

    def before_save_instance(self, instance, using_transactions, dry_run):
        instance.geom = Point(float(instance.longitude), float(instance.latitude))
        return instance
Berbera answered 30/7, 2019 at 5:40 Comment(4)
Excellent this answer helped me a lot. CheersVictualer
Good to know! Thanks!Berbera
from import_export.fields import FieldSheriff
from django.contrib.gis.geos import PointBerbera
S
1

I had some problem, similar to @Nikko. I had a really hard time doing what I wanted, and Nikko pieces of code helped. I'm not completely satisfied with what I've done but it works and maybe it can help some people. It's dirty so if someone wants to explain me what would be the right way, I'm all ears.

This code allows you to import AND export (using django-import-export), from the admin interface, a class containing a PointField (from django-geojson) by storing only the latitude and the longitude in the output file (not the all geojson file).

admin.py :

from leaflet.admin import LeafletGeoAdmin
from import_export import resources
from import_export.fields import Field
from import_export.admin import ImportExportModelAdmin
import json

from django.db import models
from djgeojson.fields import PointField

class SleepSpotResource(resources.ModelResource):
    latitude = Field(attribute='latitude', column_name='latitude')
    longitude = Field(attribute='longitude', column_name='longitude')

    class Meta:
        model = SleepSpot
        fields = ('id','album','title','start_date','end_date','latitude','longitude' )
        exclude = ('geom')
        export_order = ('id','album','title','start_date','end_date','latitude','longitude' )

    def before_save_instance(self, instance, using_transactions, dry_run):
        longitude = float(getattr(instance, 'longitude'))
        latitude = float(getattr(instance, 'latitude'))

        instance.geom = {'type': 'Point', 'coordinates': [longitude, latitude]}
        return instance

    def dehydrate_longitude(self, sleepspot):
        try:
            geomjson = sleepspot.geom
            if type(geomjson) is str:
                geomjson = json.loads(geomjson.replace("\'", "\""))
            return geomjson['coordinates'][0]
        except:
            pass

    def dehydrate_latitude(self, sleepspot):
        try:
            geomjson = sleepspot.geom
            if type(geomjson) is str:
                geomjson = json.loads(geomjson.replace("\'", "\""))
            return geomjson['coordinates'][1]
        except:
            pass

@admin.register(SleepSpot)
class SleepSpotModelAdmin(LeafletGeoAdmin, ImportExportModelAdmin):
    list_display = ('title', 'start_date', 'end_date', 'album')
    resource_class = SleepSpotResource
Sheriff answered 1/11, 2019 at 10:5 Comment(1)
Glad to know it helped you. I also have an answer for your question. I hope it also helps you. Thanks!Berbera
B
0

@Friedrich, a PointField has a method coords. I did not test this though.

I would do this:

def dehydrate_longitude(self, sleepspot):
    return sleepspot.geom.coords[0]

def dehydrate_longitude(self, sleepspot):
    return sleepspot.geom.coords[1]

as long as it is saved as PointField:

from django.contrib.gis.geos import Point
instance.geom = Point(float(instance.longitude), float(instance.latitude))

instead of a JSON

instance.geom = {'type': 'Point', 'coordinates': [longitude, latitude]}

Berbera answered 7/11, 2019 at 4:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.