导入前解析 django-import-export 中的字段

Parsing fields in django-import-export before importing

我正在使用 django-import-export 包来获取包含位置名称及其经纬度的 csv 文件。

我想从 csv 中解析经度和纬度字段,将它们转换为 django.contrib.gis.geos.Point 对象,以便我可以将其输入到我的 Location 模型的 geom 字段中。

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

这是我取得的进展,但没有成功。 必须有:

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

CSV 文件:locations.csv

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

更新 1 尝试使用 hydrate_<field_name> 但没有成功。

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

我用before_save_instance(self, instance, using_transactions, dry_run)

解决了

函数可以在将对象传递给模型之前对其进行修改。

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

我遇到了一些问题,类似于@Nikko。我真的很难做我想做的事,而 Nikko 的代码片段帮了我大忙。我对自己所做的并不完全满意,但 它有效 并且也许它可以帮助某些人。 这很脏 所以如果有人想向我解释什么是正确的方法,我会洗耳恭听。

此代码允许您通过仅存储纬度和经度从管理界面导入和导出(使用 django-import-export)一个包含 PointField(来自 django-geojson)的 class在输出文件中(不是所有 geojson 文件)。

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

@Friedrich,PointField 有一个方法 coords。虽然我没有测试这个。

我会这样做:

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

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

只要保存为PointField即可:

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

而不是 JSON

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