Geotrek-admin icon indicating copy to clipboard operation
Geotrek-admin copied to clipboard

Pouvoir dupliquer un itinéraire

Open ThibaultCCVG86 opened this issue 4 years ago • 6 comments

Bonjour,

J'ai 281 itinéraires que mes élus veulent valoriser dans trois pratiques : pédestre, équestre, VTT. J'ai saisi une fois les 281 boucles pour la randonnée pédestre. Y a t-il un moyen pour les dupliquer dans les autres pratiques ?

Merci beaucoup.

ThibaultCCVG86 avatar Feb 10 '21 14:02 ThibaultCCVG86

Cette fonctionnalité n'existe pas pour l'instant. Mais techniquement il serait envisageable de l'ajouter.

gutard avatar Feb 10 '21 15:02 gutard

Depuis la liste des itinéraires, à ajouter dans ACTIONS ? Ou alors depuis la fiche ITINÉRAIRE ? On duplique l'objet et ses infos (1-1, 1-n et n-n) et sa géométrie, mais pas ses fichiers liés.

camillemonchicourt avatar Dec 06 '21 16:12 camillemonchicourt

Dans le cadre d'une intervention effectuée avec le PN Forets, une fonction de duplication d'itinéraire a été mise en place.

Cette fonction python a pour objectif de permettre de "copier/coller" un itinéraire à partir de son ID. Pour l'utiliser, il faut copier le code ci-dessous dans un shell Geotrek (ouvrir un shell via la commande sudo geotrek shell) puis utiliser la fonction en faisant : dupicate_trek(<identifiant_du_trek_a_dupliquer>)

Cela va créer un trek nommé "COPY <nom_du_trek_copié>" qui reprend normalement les même attributs que l'itinéraire original.

Code :

from uuid import uuid4
from geotrek.trekking.models import Trek
from datetime import date


def duplicate_trek(identifiant):
    # identifiant = IDENTIFIANT_DU_TREK_A_DUPLIQUER
    trek_original = Trek.objects.get(id=identifiant)
    aggreg_original = trek_original.aggregations.all()
    trek_original.topo_object.pk = None
    trek_original.topo_object.uuid = uuid4()
    trek_original.topo_object.save()
    for a in aggreg_original.all():
        a.topo_object_id = trek_original.topo_object.pk
        a.pk = None
        a.save()
    t = Trek.objects.create(
        pk=None,
        topo_object=trek_original.topo_object,
        date_insert=date.today(),
        date_update=date.today(),
        name_fr=f"COPY {trek_original.name_fr}",
        name_en=trek_original.name_en,
        description=trek_original.description,
        description_en=trek_original.description_en,
        description_fr=trek_original.description_fr,
        published=trek_original.published,
        published_fr=trek_original.published_fr,
        published_en=trek_original.published_en,
        access=trek_original.access,
        access_fr=trek_original.access_fr,
        access_en=trek_original.access_en,
        advised_parking=trek_original.advised_parking,
        advised_parking_fr=trek_original.advised_parking_fr,
        advised_parking_en=trek_original.advised_parking_en,
        ambiance=trek_original.ambiance,
        ambiance_en=trek_original.ambiance_en,
        ambiance_fr=trek_original.ambiance_fr,
        arrival=trek_original.arrival,
        arrival_fr=trek_original.arrival_fr,
        arrival_en=trek_original.arrival_en,
        departure=trek_original.departure,
        departure_fr=trek_original.departure_fr,
        departure_en=trek_original.departure_en,
        description_teaser=trek_original.description_teaser,
        description_teaser_fr=trek_original.description_teaser_fr,
        description_teaser_en=trek_original.description_teaser_en,
        duration=trek_original.duration,
        advice=trek_original.advice,
        advice_fr=trek_original.advice_fr,
        advice_en=trek_original.advice_en,
        difficulty=trek_original.difficulty,
        difficulty_id=trek_original.difficulty_id,
        disabled_infrastructure=trek_original.disabled_infrastructure,
        disabled_infrastructure_fr=trek_original.disabled_infrastructure_fr,
        disabled_infrastructure_en=trek_original.disabled_infrastructure_en,
        eid=trek_original.eid,
        eid2=trek_original.eid2,
        route=trek_original.route,
        route_id=trek_original.route_id,
        public_transport=trek_original.public_transport,
        public_transport_fr=trek_original.public_transport_fr,
        public_transport_en=trek_original.public_transport_en,
        parking_location=trek_original.parking_location,
        reservation_system=trek_original.reservation_system,
        reservation_system_id=trek_original.reservation_system_id,
        structure=trek_original.structure,
        structure_id=trek_original.structure_id,
        practice=trek_original.practice,
        practice_id=trek_original.practice_id,
    )
    for a in trek_original.attachments.all():
        t.attachments.add(a)
        t.attachments.save()
    for ac in trek_original.accessibilities.all():
        t.accessibilities.add(ac)
    for i in trek_original.information_desks.all():
        t.information_desks.add(i)
    for la in trek_original.labels.all():
        t.labels.add(la)
    for th in trek_original.themes.all():
        t.themes.add(th)
    for poi in trek_original.pois_excluded.all():
        t.pois_excluded.add(poi)
    for ch in trek_original.trek_children.all():
        t.trek_children.add(ch)
    for pa in trek_original.trek_parents.all():
        t.trek_parents.add(pa)
    t.save()

Attention, il faut garder en tête que cette fonction n'est pas testée et ne garantie pas la création d'une copie conforme de l'itinéraire initial, il s'agit là d'un snippet de code. Dans le cadre de l'intervention pour le PN Forêts cela a correctement fonctionné mais je recommande de vérifier manuellement chaque itinéraire dupliqué pour s'assurer que les champs (et particulièrement les champs many2many) ont bien étés correctement remplis.

A terme il pourrait être envisageable d'ajouter cette fonctionnalité à Geotrek. Dans ce cas ce snippet serait une base de départ pour la fonctionnalité qui serait probablement étoffée et correctement testée.

babastienne avatar Feb 01 '22 14:02 babastienne

OK merci beaucoup pour ce retour et ce partage. En effet c'est une bonne base pour en faire une commande intégrée, testée et évolutive dans Geotrek.

Je ne connaissais pas la possibilité des commande shell Geotrek de cette manière. J'ai fait un petit test, mais j'ai surement mal écrit la commande :

geotrek@geotrek-test:~$ sudo geotrek shell
Python 3.6.9 (default, Dec  8 2021, 21:08:43) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from uuid import uuid4
>>> from geotrek.trekking.models import Trek
>>> from datetime import date
>>> 
>>> 
>>> def duplicate_trek(identifiant):
...     # identifiant = IDENTIFIANT_DU_TREK_A_DUPLIQUER
...     trek_original = Trek.objects.get(id=identifiant)
...     aggreg_original = trek_original.aggregations.all()
...     trek_original.topo_object.pk = None
...     trek_original.topo_object.uuid = uuid4()
...     trek_original.topo_object.save()
...     for a in aggreg_original.all():
...         a.topo_object_id = trek_original.topo_object.pk
...         a.pk = None
...         a.save()
...     t = Trek.objects.create(
...         pk=None,
...         topo_object=trek_original.topo_object,
...         date_insert=date.today(),
...         date_update=date.today(),
...         name_fr=f"COPY {trek_original.name_fr}",
...         name_en=trek_original.name_en,
...         description=trek_original.description,
...         description_en=trek_original.description_en,
...         description_fr=trek_original.description_fr,
...         published=trek_original.published,
...         published_fr=trek_original.published_fr,
...         published_en=trek_original.published_en,
...         access=trek_original.access,
...         access_fr=trek_original.access_fr,
...         access_en=trek_original.access_en,
...         advised_parking=trek_original.advised_parking,
...         advised_parking_fr=trek_original.advised_parking_fr,
...         advised_parking_en=trek_original.advised_parking_en,
...         ambiance=trek_original.ambiance,
...         ambiance_en=trek_original.ambiance_en,
...         ambiance_fr=trek_original.ambiance_fr,
...         arrival=trek_original.arrival,
...         arrival_fr=trek_original.arrival_fr,
...         arrival_en=trek_original.arrival_en,
...         departure=trek_original.departure,
...         departure_fr=trek_original.departure_fr,
...         departure_en=trek_original.departure_en,
...         description_teaser=trek_original.description_teaser,
...         description_teaser_fr=trek_original.description_teaser_fr,
...         description_teaser_en=trek_original.description_teaser_en,
...         duration=trek_original.duration,
...         advice=trek_original.advice,
...         advice_fr=trek_original.advice_fr,
...         advice_en=trek_original.advice_en,
...         difficulty=trek_original.difficulty,
...         difficulty_id=trek_original.difficulty_id,
...         disabled_infrastructure=trek_original.disabled_infrastructure,
...         disabled_infrastructure_fr=trek_original.disabled_infrastructure_fr,
...         disabled_infrastructure_en=trek_original.disabled_infrastructure_en,
...         eid=trek_original.eid,
...         eid2=trek_original.eid2,
...         route=trek_original.route,
...         route_id=trek_original.route_id,
...         public_transport=trek_original.public_transport,
...         public_transport_fr=trek_original.public_transport_fr,
...         public_transport_en=trek_original.public_transport_en,
...         parking_location=trek_original.parking_location,
...         reservation_system=trek_original.reservation_system,
...         reservation_system_id=trek_original.reservation_system_id,
...         structure=trek_original.structure,
...         structure_id=trek_original.structure_id,
...         practice=trek_original.practice,
...         practice_id=trek_original.practice_id,
...     )
...     for a in trek_original.attachments.all():
...         t.attachments.add(a)
...         t.attachments.save()
...     for ac in trek_original.accessibilities.all():
...         t.accessibilities.add(ac)
...     for i in trek_original.information_desks.all():
...         t.information_desks.add(i)
...     for la in trek_original.labels.all():
...         t.labels.add(la)
...     for th in trek_original.themes.all():
...         t.themes.add(th)
...     for poi in trek_original.pois_excluded.all():
...         t.pois_excluded.add(poi)
...     for ch in trek_original.trek_children.all():
...         t.trek_children.add(ch)
...     for pa in trek_original.trek_parents.all():
...         t.trek_parents.add(pa)
...     t.save()
... duplicate_trek(786)
  File "<console>", line 85
    duplicate_trek(786)
                 ^
SyntaxError: invalid syntax

camillemonchicourt avatar Feb 01 '22 16:02 camillemonchicourt

Il faut d'abord finir la fonction duplicate_trek() avant de l'appeler.

Ici, tu n'as pas fait ENTER, avant de l'appeler.

Tu dois avoir dans ton shell : >>> duplicate_trek(786) et non pas . . . duplicate_trek(786) Les . . . signifient que tu ecris quelque chose sur plusieurs lignes.

LePetitTim avatar Mar 31 '22 11:03 LePetitTim

OK bien vu, merci. J'avais fait un ENTER après avoir défini la fonction, mais il fallait le faire une deuxième fois. Et là ça fonctionne en effet !

Il a juste fallu renommer les champs disabled_infrastructures en accessibility_infrastructures car on a changé le nom de ce champs entre temps :

from uuid import uuid4
from geotrek.trekking.models import Trek
from datetime import date


def duplicate_trek(identifiant):
    # identifiant = IDENTIFIANT_DU_TREK_A_DUPLIQUER
    trek_original = Trek.objects.get(id=identifiant)
    aggreg_original = trek_original.aggregations.all()
    trek_original.topo_object.pk = None
    trek_original.topo_object.uuid = uuid4()
    trek_original.topo_object.save()
    for a in aggreg_original.all():
        a.topo_object_id = trek_original.topo_object.pk
        a.pk = None
        a.save()
    t = Trek.objects.create(
        pk=None,
        topo_object=trek_original.topo_object,
        date_insert=date.today(),
        date_update=date.today(),
        name_fr=f"COPY {trek_original.name_fr}",
        name_en=trek_original.name_en,
        description=trek_original.description,
        description_en=trek_original.description_en,
        description_fr=trek_original.description_fr,
        published=trek_original.published,
        published_fr=trek_original.published_fr,
        published_en=trek_original.published_en,
        access=trek_original.access,
        access_fr=trek_original.access_fr,
        access_en=trek_original.access_en,
        advised_parking=trek_original.advised_parking,
        advised_parking_fr=trek_original.advised_parking_fr,
        advised_parking_en=trek_original.advised_parking_en,
        ambiance=trek_original.ambiance,
        ambiance_en=trek_original.ambiance_en,
        ambiance_fr=trek_original.ambiance_fr,
        arrival=trek_original.arrival,
        arrival_fr=trek_original.arrival_fr,
        arrival_en=trek_original.arrival_en,
        departure=trek_original.departure,
        departure_fr=trek_original.departure_fr,
        departure_en=trek_original.departure_en,
        description_teaser=trek_original.description_teaser,
        description_teaser_fr=trek_original.description_teaser_fr,
        description_teaser_en=trek_original.description_teaser_en,
        duration=trek_original.duration,
        advice=trek_original.advice,
        advice_fr=trek_original.advice_fr,
        advice_en=trek_original.advice_en,
        difficulty=trek_original.difficulty,
        difficulty_id=trek_original.difficulty_id,
        accessibility_infrastructure=trek_original.accessibility_infrastructure,
        accessibility_infrastructure_fr=trek_original.accessibility_infrastructure_fr,
        accessibility_infrastructure_en=trek_original.accessibility_infrastructure_en,
        eid=trek_original.eid,
        eid2=trek_original.eid2,
        route=trek_original.route,
        route_id=trek_original.route_id,
        public_transport=trek_original.public_transport,
        public_transport_fr=trek_original.public_transport_fr,
        public_transport_en=trek_original.public_transport_en,
        parking_location=trek_original.parking_location,
        reservation_system=trek_original.reservation_system,
        reservation_system_id=trek_original.reservation_system_id,
        structure=trek_original.structure,
        structure_id=trek_original.structure_id,
        practice=trek_original.practice,
        practice_id=trek_original.practice_id,
    )
    for a in trek_original.attachments.all():
        t.attachments.add(a)
        t.attachments.save()
    for ac in trek_original.accessibilities.all():
        t.accessibilities.add(ac)
    for i in trek_original.information_desks.all():
        t.information_desks.add(i)
    for la in trek_original.labels.all():
        t.labels.add(la)
    for th in trek_original.themes.all():
        t.themes.add(th)
    for poi in trek_original.pois_excluded.all():
        t.pois_excluded.add(poi)
    for ch in trek_original.trek_children.all():
        t.trek_children.add(ch)
    for pa in trek_original.trek_parents.all():
        t.trek_parents.add(pa)
    t.save()

J'aurai aussi pu ajouter les nouveaux champs liés à l'accessibilité pour affiner et compléter, mais pas fait cette fois-ci pour mes tests.

camillemonchicourt avatar Apr 06 '22 22:04 camillemonchicourt

La fonctionnalité de duplication d'itinéraires, mais aussi des autres objets a été intégrée dans la version 2.95.0, directement dans l'interface sur les fiches objets. Voir https://github.com/GeotrekCE/Geotrek-admin/issues/3105#issuecomment-1404323251 pour les premiers retours de tests.

camillemonchicourt avatar Jan 25 '23 22:01 camillemonchicourt