Modification des stages, bases pour la gestion des lieux

This commit is contained in:
Evarin 2017-04-11 00:20:14 +02:00
parent 44ddb67332
commit e151fc3d1e
7 changed files with 204 additions and 40 deletions

View file

@ -36,7 +36,7 @@ class Normalien(models.Model):
verbose_name_plural = u"Profils élèves" verbose_name_plural = u"Profils élèves"
def __unicode__(self): def __unicode__(self):
return unicode("%s (%s)", self.nom, self.user.username) return u"%s (%s)" % (self.nom, self.user.username)
# Hook à la création d'un nouvel utilisateur : récupération de ses infos par LDAP # Hook à la création d'un nouvel utilisateur : récupération de ses infos par LDAP
def create_user_profile(sender, instance, created, **kwargs): def create_user_profile(sender, instance, created, **kwargs):
@ -96,11 +96,12 @@ class Lieu(models.Model):
# Coordonnées # Coordonnées
objects = geomodels.GeoManager() # Requis par GeoDjango objects = geomodels.GeoManager() # Requis par GeoDjango
coord = geomodels.PointField(u"Coordonnées", coord = geomodels.PointField(u"Coordonnées",
geography=True) geography=True,
srid = 4326)
def __unicode__(self): def __unicode__(self):
return u"%s (%s)" % (self.name, self.ville) return u"%s (%s)" % (self.nom, self.ville)
class Meta: class Meta:
verbose_name = "Lieu" verbose_name = "Lieu"
@ -161,7 +162,7 @@ class Stage(models.Model):
return reverse('avisstage:stage', self) return reverse('avisstage:stage', self)
def __unicode__(self): def __unicode__(self):
return u"%s (par %s)" % (self.sujet, self.auteur.user_id) return u"%s (par %s)" % (self.sujet, self.auteur.user.username)
class Meta: class Meta:
verbose_name = "Stage" verbose_name = "Stage"
@ -173,34 +174,35 @@ class Stage(models.Model):
class AvisStage(models.Model): class AvisStage(models.Model):
stage = models.OneToOneField(Stage, related_name="avis_stage") stage = models.OneToOneField(Stage, related_name="avis_stage")
chapo = models.TextField(u"En quelques mots") chapo = models.TextField(u"En quelques mots", blank=True)
avis_personnes = RichTextField(u"Les encadrants et l'équipe") avis_personnes = RichTextField(u"Les encadrants et l'équipe", blank=True)
avis_sujet = RichTextField(u"Le sujet de stage") avis_sujet = RichTextField(u"Le sujet de stage", blank=True)
avis_admin = RichTextField(u"Formalités et administration") avis_admin = RichTextField(u"Formalités et administration", blank=True)
les_plus = models.TextField(u"Les plus du stage") les_plus = models.TextField(u"Les plus du stage", blank=True)
les_moins = models.TextField(u"Les moins du stage") les_moins = models.TextField(u"Les moins du stage", blank=True)
def __unicode__(self): def __unicode__(self):
return u"Avis sur {%s} par %" % (stage.sujet, stage.auteur.user_id) return u"Avis sur {%s} par %" % (stage.sujet, stage.auteur.user.username)
class AvisLieu(models.Model): class AvisLieu(models.Model):
stage = models.ForeignKey(Stage) stage = models.ForeignKey(Stage)
lieu = models.ForeignKey(Lieu) lieu = models.ForeignKey(Lieu)
order = models.IntegerField("Ordre", default=0) order = models.IntegerField("Ordre", default=0)
chapo = models.TextField(u"En quelques mots") chapo = models.TextField(u"En quelques mots", blank=True)
avis_lieustage = RichTextField(u"Le lieu du stage") avis_lieustage = RichTextField(u"Le lieu du stage", blank=True)
avis_pratique = RichTextField(u"S'installer - conseils pratiques") avis_pratique = RichTextField(u"S'installer - conseils pratiques",
avis_tourisme = RichTextField(u"Dans les parages") blank=True)
avis_tourisme = RichTextField(u"Dans les parages", blank=True)
les_plus = models.TextField(u"Les plus du lieu") les_plus = models.TextField(u"Les plus du lieu", blank=True)
les_moins = models.TextField(u"Les moins du lieu") les_moins = models.TextField(u"Les moins du lieu", blank=True)
class Meta: class Meta:
verbose_name = "Avis sur un lieu de stage" verbose_name = "Avis sur un lieu de stage"
verbose_name_plural = "Avis sur un lieu de stage" verbose_name_plural = "Avis sur un lieu de stage"
def __unicode__(self): def __unicode__(self):
return u"Avis sur {%s} par %" % (lieu.nom, stage.auteur.user_id) return u"Avis sur {%s} par %s" % (self.lieu.nom, self.stage.auteur.user_id)

View file

@ -3,7 +3,7 @@
{% block content %} {% block content %}
<h1>Profil de {{ object.nom }}</h1> <h1>Profil de {{ object.nom }}</h1>
{% if object.user == request.user %} {% if object.user == user %}
<p><a href="{% url "avisstage:profil_edit" %}">Modifier mes infos</a></p> <p><a href="{% url "avisstage:profil_edit" %}">Modifier mes infos</a></p>
{% endif %} {% endif %}
<p><b>Promotion :</b> {{ object.promotion }}</p> <p><b>Promotion :</b> {{ object.promotion }}</p>

View file

@ -2,22 +2,32 @@
{% load staticfiles %} {% load staticfiles %}
{% block content %} {% block content %}
<h1>Profil de {{ object.nom }}</h1> <h1>{{ object.sujet }}</h1>
{% if object.user == request.user %} {% if object.auteur == user.profil %}
<p><a href="{% url "avisstage:profil_edit" %}">Modifier mes infos</a></p> <p><a href="{% url "avisstage:stage_edit" object.id %}">Modifier ce stage</a></p>
{% endif %} {% endif %}
<p><b>Promotion :</b> {{ object.promotion }}</p> <article class="stage">
<p>Adresse de contact : <a href="mailto:{{ object.mail }}">{{ object.mail }}</a></p> <section class="misc">
<article> <h2>À propos du stage</h2>
<h2>Ses stages</h2> <p>{{ object.auteur.nom }} a fait ce stage du {{ object.date_debut }} au {{ object.date_fin }}, supervisé par {{ object.encadrants }}</p>
<ul class="stagelist"> <ul class="infos">
{% for stage in object.stages_publics %} {% for matiere in object.matieres.all %}
<li> <li class="matiere">{{ matiere.nom }}</li>
<a href="{% url "avisstage:stage" stage.id %}"> {% endfor %}
{{ stage.sujet }} {% for thematique in object.thematiques.all %}
</a> <li class="thematique">{{ thematique.name }}</li>
</li> {% endfor %}
{% endfor %} </ul>
</ul> </section>
{% with object.avis_stage as avis %}
<section class="avis">
{% if avis.chapo %}
<p class="chapo">
{{ avis.chapo }}
</p>
{% endif %}
</section>
{% endwith %}
</article> </article>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,24 @@
{% extends "avisstage/base.html" %}
{% load staticfiles %}
{% block extra_head %}
<link href="{% static "jquery-autosuggest/css/autoSuggest-upshot.css" %}"
type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript"
src="{% static "jquery-autosuggest/js/jquery.autoSuggest.minified.js" %}"> </script>
<script type="text/javascript">
$( function() {
$( ".datepicker" ).datepicker({ dateFormat: 'dd/mm/yy' });
} );
</script>
{% endblock %}
{% block content %}
<h1>Ajouter un stage</h1>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" />
</form>
{% endblock %}

View file

@ -6,7 +6,9 @@ urlpatterns = [
url(r'^perso/$', views.perso, name='perso'), url(r'^perso/$', views.perso, name='perso'),
url(r'^stage/nouveau/$', views.StageAjout.as_view(), name='stage_ajout'), url(r'^stage/nouveau/$', views.StageAjout.as_view(), name='stage_ajout'),
url(r'^stage/(?P<pk>\w+)/$', views.StageView.as_view(), name='stage'), url(r'^stage/(?P<pk>\w+)/$', views.StageView.as_view(), name='stage'),
url(r'^stage/(?P<pk>\w+)/edit/$', views.StageEdit.as_view(), name='stage_edit'),
url(r'^lieu/ajout/$', views.LieuAjout.as_view(), name='lieu_ajout'),
url(r'^profil/show/(?P<username>\w+)/$', views.ProfilView.as_view(), url(r'^profil/show/(?P<username>\w+)/$', views.ProfilView.as_view(),
name='profil'), name='profil'),
url(r'^profil/edit/$', views.ProfilEdit.as_view(), name='profil_edit'), url(r'^profil/edit/$', views.ProfilEdit.as_view(), name='profil_edit'),

View file

@ -1,3 +1,5 @@
# coding: utf-8
from django.shortcuts import render from django.shortcuts import render
from django.views.generic import DetailView from django.views.generic import DetailView
@ -7,7 +9,8 @@ from django.urls import reverse
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from braces.views import LoginRequiredMixin from braces.views import LoginRequiredMixin
from avisstage.models import Normalien, Stage from avisstage.models import Normalien, Stage, Lieu, AvisLieu, AvisStage
from widget import LatLonField
# Page d'accueil # Page d'accueil
def index(request): def index(request):
@ -49,15 +52,58 @@ class StageForm(forms.ModelForm):
class Meta: class Meta:
model = Stage model = Stage
fields = ['sujet', 'date_debut', 'date_fin', 'type_stage', 'thematiques', 'matieres', 'encadrants'] fields = ['sujet', 'date_debut', 'date_fin', 'type_stage', 'thematiques', 'matieres', 'encadrants', 'lieux']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request") if "request" in kwargs:
self.request = kwargs.pop("request")
super(StageForm, self).__init__(*args, **kwargs) super(StageForm, self).__init__(*args, **kwargs)
if hasattr(self, 'instance'):
self.prev_lieux = self.instance.avislieu_set.all()
else:
self.prev_lieux = None
def save(self, commit=True): def save(self, commit=True):
self.instance.auteur = self.request.user.profil if self.instance.id is None:
super(StageForm, self).save(commit=commit) self.instance.auteur = self.request.user.profil
stage = super(StageForm, self).save(commit=False)
if commit:
stage.save()
# Lecture des lieux, conservation des critiques précédentes
alieux = self.cleaned_data['lieux']
new_lieux = []
#print self.instance.lieux
if not (self.prev_lieux is None) and len(self.prev_lieux) > 0:
old_avislieux = {avis.lieu_id: avis for avis in self.prev_lieux}
for (k, nlieu) in enumerate(alieux):
if nlieu in old_avislieux:
# Ce lien existait déjà avant : rien à faire
del old_avislieux[nlieu]
else:
# C'est un nouveau lien
new_lieux.append(nlieu)
old_avislieux = old_avislieux.values()
for k, avislieu in enumerate(old_avislieux):
if k > len(new_lieux):
# Avis à supprimer
avislieu.delete()
else:
# On récupère le(s) avis pour le(s) nouveau(x) lieu(x)
avislieu.lieu = new_lieux[k]
avislieu.save()
new_lieux = new_lieux[len(old_avislieux):]
else:
new_lieux = alieux
print(new_lieux)
# On crée les nouveaux avislieu qui vont bien
AvisLieu.objects.bulk_create([AvisLieu(lieu=lieu, stage=stage) for lieu in new_lieux])
class StageAjout(CreateView, LoginRequiredMixin): class StageAjout(CreateView, LoginRequiredMixin):
model = Stage model = Stage
@ -69,10 +115,43 @@ class StageAjout(CreateView, LoginRequiredMixin):
kwargs.update({'request': self.request}) kwargs.update({'request': self.request})
return kwargs return kwargs
class StageEdit(UpdateView, LoginRequiredMixin):
model = Stage
form_class = StageForm
template_name = 'avisstage/formulaires/stage.html'
def get_queryset(self):
# Autorise les modifications des seuls stages qu'on "possède"
queryset = super(StageEdit, self).get_queryset()
return queryset.filter(auteur=self.request.user.profil)
def get_form_kwargs(self):
kwargs = super(StageEdit, self).get_form_kwargs()
kwargs.update({'request': self.request})
return kwargs
def get_success_url(self):
return reverse('avisstage:stage', self.instance.id)
class StageView(DetailView, LoginRequiredMixin): class StageView(DetailView, LoginRequiredMixin):
model = Stage model = Stage
template_name = 'avisstage/detail/stage.html' template_name = 'avisstage/detail/stage.html'
# Lieux des stages
class LieuForm(forms.ModelForm):
coord = LatLonField()
class Meta:
model = Lieu
fields = ['nom', 'type_lieu', 'ville', 'pays', 'coord']
class LieuAjout(CreateView, LoginRequiredMixin):
model = Lieu
form_class = LieuForm
template_name = 'avisstage/formulaires/lieu.html'
def recherche(request): def recherche(request):
return render(request, 'avisstage/recherche.html') return render(request, 'avisstage/recherche.html')

47
avisstage/widget.py Normal file
View file

@ -0,0 +1,47 @@
from django import forms
from django.core import validators
class LatLonWidget(forms.MultiWidget):
"""
A Widget that splits Point input into two latitude/longitude boxes.
"""
def __init__(self, attrs=None, date_format=None, time_format=None):
widgets = (forms.TextInput(attrs=attrs),
forms.TextInput(attrs=attrs))
super(LatLonWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
return tuple(reversed(value.coords))
return (None, None)
class LatLonField(forms.MultiValueField):
widget = LatLonWidget
srid = 4326
default_error_messages = {
'invalid_latitude' : (u'Entrez une latitude valide.'),
'invalid_longitude' : (u'Entrez une longitude valide.'),
}
def __init__(self, *args, **kwargs):
fields = (forms.FloatField(min_value=-90, max_value=90),
forms.FloatField(min_value=-180, max_value=180))
super(LatLonField, self).__init__(fields, *args, **kwargs)
def compress(self, data_list):
if data_list:
# Raise a validation error if latitude or longitude is empty
# (possible if LatLongField has required=False).
if data_list[0] in validators.EMPTY_VALUES:
raise forms.ValidationError(self.error_messages['invalid_latitude'])
if data_list[1] in validators.EMPTY_VALUES:
raise forms.ValidationError(self.error_messages['invalid_longitude'])
# SRID=4326;POINT(1.12345789 1.123456789)
srid_str = 'SRID=%d'%self.srid
point_str = 'POINT(%f %f)'%tuple(reversed(data_list))
return ';'.join([srid_str, point_str])
return None