Bonjour à tous,
Je suis actuellement en train de développer une base de donnée naturaliste en ligne pour collecter les données d'études sur les chauves-souris (projet dbChiro[web], tout le code est sur framagit). Elle est tourne principalement avec sur Django (1.11) et django-leaflet et crispy-forms pour les formulaires.
Une démo est disponible ici: http://demo.dbchiro.org/session/4/detail
- login: observateur
- mdp: Observ#dbChiro*
Je précise, je débute avec Python et Django depuis seulement 2-3 mois en autodidacte.
Dans cet base, je rencontre un problème à l'enregistrement d'une donnée via les gabarits créés (donnée espèce, étape 3 de la liste suivante) sans parvenir à en comprendre la cause.
La saisie des données s’effectue en 4 étapes:
- Création d'une nouvelle localité (modèle "Place", localisation géographique de la donnée) > renvoie vers une fiche détaillée de la localité avec liste des sessions réalisées et possibilité d'ajout d'une session
- Création d'une nouvelle session correspondant à une date et une méthode d'inventaire (modèle "Session", clé étrangère vers le modèle précédent "Place") > renvoie vers une fiche détaillée de la session d'inventaire avec liste des espèces observées et possibilité d'ajout d'une espèce (cf. pJ 117)
- Création d'une nouvelle espèce (cf. pJ 118) (modèle "Sighting", clé étrangère vers "Session") > Renvoie vers la fiche détaillée de la session
- Création de détails de comptages par espèce (modèle "CountDetail", clé étrangère vers "Sighting") > Renvoie non défini pour le moment.
Aucun pb pour créer mes localités et mes sessions. Par contre, lors de la création d'une donnée espèce (via le formulaire du gabarit), l'enregistrement de la donnée ne s'effectue pas et me renvoie systématiquement vers le formulaire de saisie (la page en cours donc). Je pense que le pb vient de ma vue (fonction sighting_create) mais je ne parviens pas à identifier la cause. Je vous mets les principaux codes concernés par cette étape.
Quelqu'un pourrait-il m'aiguiller?
Merci
> Les modèles Sighting et Session "Session"
> Le formulaire généré avec Crispy Forms Foundation
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 #sights/models.py class Session(models.Model): id_session = models.AutoField(primary_key=True) name = models.CharField( max_length=150, blank=True, verbose_name='Intitulé de la session') method = models.ForeignKey( DictMethod, models.DO_NOTHING, null=True, verbose_name='Méthode utilisée') place = models.ForeignKey( Place, models.DO_NOTHING, verbose_name='Localité associée') date_start = models.DateField( verbose_name='Date de début') time_start = models.TimeField( blank=True, null=True, verbose_name='Heure de début') date_end = models.DateField( blank=True, null=True, verbose_name='Date de fin') time_end = models.TimeField( blank=True, null=True, verbose_name='Heure de fin') main_observer = models.ForeignKey( User, on_delete=DO_NOTHING, related_name='mainobs') other_observer = models.ManyToManyField( User, blank=True, related_name='otherobs') comment = models.TextField(blank=True, null=True, verbose_name='Commentaire') timestamp_create = models.DateTimeField( auto_now_add=True, editable=False) timestamp_update = models.DateTimeField( auto_now=True, editable=False) creator = models.ForeignKey(User, null=True, editable=False) def __str__(self): return "%s ∙ %s ∙ %s" % (self.place, datetime.date(self.date_start.year, self.date_start.month, self.date_start.day), self.method) def get_absolute_url(self): return reverse('session_detail', kwargs={'pk': self.id_session}) class Meta: verbose_name = "2 ∙ Session d'inventaire/observations" verbose_name_plural = "2 ∙ Sessions d'inventaire/observations" unique_together = ["place", "method", "date_start"] class Sighting(models.Model): id_sighting = models.AutoField('id unique', primary_key=True) session = models.ForeignKey( Session, on_delete=models.CASCADE, verbose_name='Session associée') codesp = models.ForeignKey( DictSpecie, on_delete=DO_NOTHING, verbose_name='Espèce ou groupe d\'espèce') total_count = models.IntegerField('Nombre total', blank=True, null=True) transmitter = models.ForeignKey( Transmitter, models.DO_NOTHING, blank=True, null=True, verbose_name='Emetteur de télémétrie') breed_colo = models.NullBooleanField( verbose_name='Colonie de reproduction') observer = models.ForeignKey( User, related_name="+", verbose_name='Observateur') id_fromsrc = models.CharField( 'id unique de la bdd source', max_length=100, blank=True, null=True) bdsource = models.CharField( 'bdd source', max_length=100, blank=True, null=True) comment = models.TextField(blank=True, null=True, verbose_name='Commentaire') timestamp_create = models.DateTimeField( auto_now_add=True, editable=False) timestamp_update = models.DateTimeField( auto_now=True, editable=False) creator = models.ForeignKey(User, null=True, editable=False) def __str__(self): return "%s ∙ %s ∙ %s" % (self.session, self.codesp, self.total_count) def get_absolute_url(self): return reverse('session_detail', kwargs={'pk': self.session.id_session}) class Meta: verbose_name = "3 ∙ Observation" verbose_name_plural = "3 ∙ Observations" permissions = ( ("view_sighting", "Peut voir les observations"), ) unique_together = ["codesp", "session"]
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #sights/forms.py class SightingForm(forms.ModelForm): class Meta: model = Sighting fields = '__all__' def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_method = 'post' self.helper.form_action = 'submit' self.helper.layout = Layout(AccordionHolder( AccordionItem('Espèces', Row( Column('codesp', css_class='medium-6 small-12'), Column('total_count', css_class='medium-6 small-12'), Column( 'breed_colo', css_class='medium-6 small-6'), Column('observer', css_class='medium-6 small-6'), ), ), AccordionItem( 'Autres informations', Row( Column('bdsource', css_class='medium-4 small-12', readonly=True), Column('id_fromsrc', readonly=True, css_class='medium-4 small-12'), Column('transmitter', css_class='medium-4 small-12') ), ), AccordionItem( 'Commentaire', Row( Column('comment', css_class='large-12'), ), ), ), ButtonHolder( Submit('submit', 'Enregistrer', css_class='button'), ), ) super(SightingForm, self).__init__(*args, **kwargs)
> Les vues pour la création d'une session (session_create) et d'une observation (sighting_create
Et le gabarit
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #sights/views.py @login_required() def session_create(request, pk): form = SessionForm(request.POST or None, initial={ 'main_observer': request.user}) place = get_object_or_404(Place, pk=pk) if form.is_valid(): place_session = place.session_set.all() for s in place_session: if s.name == form.cleaned_data.get("name"): context = { 'place': place, 'form': form, 'error_message': 'Cette session existe déjà', } return render(request, 'session_create_form.html', context) session = form.save(commit=False) session.place = place session.creator = request.user session.name = "loc%s_%s_%s_%s" % (session.place_id, datetime.date( session.date_start.year, session.date_start.month, session.date_start.day), session.method.code, session.main_observer.username) session.save() return render(request, 'session_detail.html', {'sessiondetail': session, 'place': place}) context = { 'place': place, 'form': form, } return render(request, 'session_create_form.html', context) @login_required() def sighting_create(request, pk): form = SightingForm(request.POST or None, initial={ 'observer': request.user}) session = get_object_or_404(Session, pk=pk) if form.is_valid(): sighting = form.save(commit=False) sighting.session = session sighting.creator = request.user sighting.save() return render(request, 'session_detail.html', {'sessiondetail': session}) context = { 'session': session, 'form': form, } return render(request, 'sighting_create_form.html', context)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 {% extends 'base.html' %} {% load crispy_forms_tags %} {% block content %} <h1><i class="fi-eye"></i> Création d'une observation</h1> <form action="" method="post" enctype="multipart/form-data">{% csrf_token %} <div class="input-group"> <span class="input-group-label"><i class="fi-marker"></i></span> <input class="input-group-field" value="{{ session.name }}" type="text" placeholder="{{ session.name }}" readonly> <div class="input-group-button"> <a href="{% url 'session_detail' pk=session.id_session %}" class="button"><i class="fi-info"></i></a> </div> </div> <p><strong>{{ form.error }}</strong></p> {{ form.media }} {% crispy form %} </form> <br /> {% endblock %}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #sights/urls.py # Session relative URLS url(r'^place/(?P<pk>[0-9]+)/session/add$', session_create, name='create_session'), url(r'^session/(?P<pk>[0-9]+)/detail$', session_detail, name='session_detail'), url(r'^session/(?P<pk>[0-9]+)/update$', SessionUpdate.as_view(), name='session_update'), url(r'^session/(?P<pk>[0-9]+)/delete$', SessionDelete.as_view(), name='session_delete'), # Sighting relative URLS url(r'^session/(?P<pk>[0-9]+)/sighting/add$', sighting_create, name='sighting_create'),
Partager