0

GeoDjangoを使用してアプリケーションを構築していますが、次の問題があります。

GPXファイルからトラックデータを読み取る必要があり、それらのデータはモデルのMultiLineStringFieldフィールドに保存する必要があります。これは、ユーザーがGPXファイルをアップロードする管理インターフェースで発生する必要があります

私はこれを達成しようとしています。つまり、ファイルから取得したデータをMultiLineStringFieldに割り当て、他のフィールドはフォームから値を取得する必要があります。

私のモデルは:

class GPXTrack(models.Model):
    nome = models.CharField("Nome", blank = False, max_length = 255)
    slug = models.SlugField("Slug", blank = True)
    # sport natura arte/cultura
    tipo = models.CharField("Tipologia", blank = False, max_length = 2, choices=TIPOLOGIA_CHOICES)
    descrizione = models.TextField("Descrizione", blank = True)

    gpx_file = models.FileField(upload_to = 'uploads/gpx/')
    track = models.MultiLineStringField(blank = True)
    objects = models.GeoManager()
    published = models.BooleanField("Pubblicato")
    rel_files = generic.GenericRelation(MyFiles)
     #publish_on = models.DateTimeField("Pubblicare il", auto_now_add = True)

    created = models.DateTimeField("Created", auto_now_add = True)
    updated = models.DateTimeField("Updated", auto_now = True)

    class Meta:
       #verbose_name = "struttura'"
       #verbose_name_plural = "strutture"
       ordering = ['-created']

    def __str__(self):
        return str(self.nome)

    def __unicode__(self):
        return '%s' % (self.nome)

    def put(self):
      self.slug = sluggy(self.nome)

      key = super(Foresta, self).put()
      # do something after save
      return key

admin.pyファイルで、saveメソッドを次のように上書きしました。

    from django.contrib.gis import admin
from trails.models import GPXPoint, GPXTrack
from django.contrib.contenttypes import generic
from django.contrib.gis.gdal import DataSource
#from gpx_mapping import GPXMapping
from django.contrib.gis.utils import LayerMapping
from django.template import RequestContext
import tempfile
import os
import pprint

class GPXTrackAdmin(admin.OSMGeoAdmin):
    list_filter = ( 'tipo', 'published')
    search_fields = ['nome']
    list_display = ('nome', 'tipo', 'published', 'gpx_file')
    inlines = [TrackImagesInline, TrackFilesInline]
    prepopulated_fields = {"slug": ("nome",)}

    def save_model(self, request, obj, form, change):
        """When creating a new object, set the creator field.
        """
        if 'gpx_file' in request.FILES:
            # Get
            gpxFile = request.FILES['gpx_file']
            # Save
            targetPath = tempfile.mkstemp()[1]
            destination = open(targetPath, 'wt')
            for chunk in gpxFile.chunks():
                destination.write(chunk)
            destination.close()

            #define fields of interest for LayerMapping
            track_point_mapping = {'timestamp' : 'time',
                                   'point' : 'POINT',
                          }

            track_mapping = {'track' : 'MULTILINESTRING'}

            gpx_file = DataSource(targetPath)
            mytrack = LayerMapping(GPXTrack, gpx_file, track_mapping, layer='tracks')
            mytrack.save()

            #remove the temp file saved
            os.remove(targetPath)
            orig = GPXTrack.objects.get(pk=mytrack.pk)
            #assign the parsed values from LayerMapping to the appropriate Field
            obj.track = orig.track
            obj.save()

私の知る限りでは:

  1. LayerMappingを使用してフィールドを更新することはできませんが、新しいフィールドを保存するためにのみ使用できます
  2. LayerMappingオブジェクトの特定のフィールド(つまり、上記のコード:mytrack.track )にアクセスして、model_saveメソッドでその値をモデルフィールド(つまり、obj.track )に割り当てることができません。
  3. LayerMapping.mappingにマップされていないフィールドのフォームで渡された値で更新するために、最後に保存されたLayerMappingオブジェクト(つまり、上記のコード:mytrack.pk )の主キーを取得できません。

それなら何ができますか?!?!

4

1 に答える 1

0

LayerMappingをサブクラス化して、取得したデータを保存する代わりに、使用または操作のためにそれらを返すメソッドget_values()を追加しました。get_valuesメソッドは、代わりに値を返すLayerMapping :: save()メソッドのコピーです。それらを保存します。django1.5を使用しています

import os
from django.contrib.gis.utils import LayerMapping
import sys
class MyMapping(LayerMapping):
    def get_values(self, verbose=False, fid_range=False, step=False,
         progress=False, silent=False, stream=sys.stdout, strict=False):
        """
        Returns the contents from the OGR DataSource Layer 
        according to the mapping dictionary given at initialization.

        Keyword Parameters:
         verbose:
           If set, information will be printed subsequent to each model save
           executed on the database.

         fid_range:
           May be set with a slice or tuple of (begin, end) feature ID's to map
           from the data source.  In other words, this keyword enables the user
           to selectively import a subset range of features in the geographic
           data source.

         step:
           If set with an integer, transactions will occur at every step
           interval. For example, if step=1000, a commit would occur after
           the 1,000th feature, the 2,000th feature etc.

         progress:
           When this keyword is set, status information will be printed giving
           the number of features processed and sucessfully saved.  By default,
           progress information will pe printed every 1000 features processed,
           however, this default may be overridden by setting this keyword with an
           integer for the desired interval.

         stream:
           Status information will be written to this file handle.  Defaults to
           using `sys.stdout`, but any object with a `write` method is supported.

         silent:
           By default, non-fatal error notifications are printed to stdout, but
           this keyword may be set to disable these notifications.

         strict:
           Execution of the model mapping will cease upon the first error
           encountered.  The default behavior is to attempt to continue.
        """     
            # Getting the default Feature ID range.
        default_range = self.check_fid_range(fid_range)

        # Setting the progress interval, if requested.
        if progress:
            if progress is True or not isinstance(progress, int):
                progress_interval = 1000
            else:
                progress_interval = progress

        # Defining the 'real' save method, utilizing the transaction
        # decorator created during initialization.
        @self.transaction_decorator
        def _get_values(feat_range=default_range, num_feat=0, num_saved=0):
            if feat_range:
                layer_iter = self.layer[feat_range]
            else:
                layer_iter = self.layer

            for feat in layer_iter:
                num_feat += 1
                # Getting the keyword arguments
                try:
                    kwargs = self.feature_kwargs(feat)
                except LayerMapError, msg:
                    # Something borked the validation
                    if strict: raise
                    elif not silent:
                        stream.write('Ignoring Feature ID %s because: %s\n' % (feat.fid, msg))
                else:
                    # Constructing the model using the keyword args
                    is_update = False
                    if self.unique:
                        # If we want unique models on a particular field, handle the
                        # geometry appropriately.
                        try:
                            # Getting the keyword arguments and retrieving
                            # the unique model.
                            u_kwargs = self.unique_kwargs(kwargs)
                            m = self.model.objects.using(self.using).get(**u_kwargs)
                            is_update = True

                            # Getting the geometry (in OGR form), creating
                            # one from the kwargs WKT, adding in additional
                            # geometries, and update the attribute with the
                            # just-updated geometry WKT.
                            geom = getattr(m, self.geom_field).ogr
                            new = OGRGeometry(kwargs[self.geom_field])
                            for g in new: geom.add(g)
                            setattr(m, self.geom_field, geom.wkt)
                        except ObjectDoesNotExist:
                            # No unique model exists yet, create.
                            m = self.model(**kwargs)
                    else:
                        m = self.model(**kwargs)

                    try:
                        # Attempting to save.
                        pippo = kwargs

                        num_saved += 1
                        if verbose: stream.write('%s: %s\n' % (is_update and 'Updated' or 'Saved', m))
                    except SystemExit:
                        raise
                    except Exception, msg:
                        if self.transaction_mode == 'autocommit':
                            # Rolling back the transaction so that other model saves
                            # will work.
                            transaction.rollback_unless_managed()
                        if strict:
                            # Bailing out if the `strict` keyword is set.
                            if not silent:
                                stream.write('Failed to save the feature (id: %s) into the model with the keyword arguments:\n' % feat.fid)
                                stream.write('%s\n' % kwargs)
                            raise
                        elif not silent:
                            stream.write('Failed to save %s:\n %s\nContinuing\n' % (kwargs, msg))

                # Printing progress information, if requested.
                if progress and num_feat % progress_interval == 0:
                    stream.write('Processed %d features, saved %d ...\n' % (num_feat, num_saved))

            # Only used for status output purposes -- incremental saving uses the
            # values returned here.
            return pippo

        nfeat = self.layer.num_feat
        if step and isinstance(step, int) and step < nfeat:
            # Incremental saving is requested at the given interval (step)
            if default_range:
                raise LayerMapError('The `step` keyword may not be used in conjunction with the `fid_range` keyword.')
            beg, num_feat, num_saved = (0, 0, 0)
            indices = range(step, nfeat, step)
            n_i = len(indices)

            for i, end in enumerate(indices):
                # Constructing the slice to use for this step; the last slice is
                # special (e.g, [100:] instead of [90:100]).
                if i + 1 == n_i: step_slice = slice(beg, None)
                else: step_slice = slice(beg, end)

                try:
                    pippo = _get_values(step_slice, num_feat, num_saved)
                    beg = end
                except:
                    stream.write('%s\nFailed to save slice: %s\n' % ('=-' * 20, step_slice))
                    raise
        else:
            # Otherwise, just calling the previously defined _save() function.
            return _get_values()

カスタムのsaveまたはsave_modelメソッドでは、次を使用できます。

        track_mapping = {'nome': 'name',
                         'track' : 'MULTILINESTRING'}

        targetPath = "/my/gpx/file/path.gpx"
        gpx_file = DataSource(targetPath)

        mytrack = MyMapping(GPXTrack, gpx_file, track_mapping, layer='tracks')

        pippo = mytrack.get_values()
        obj.track = pippo['track']
于 2013-04-04T09:59:43.010 に答える