Modification des stages, bases pour la gestion des lieux
This commit is contained in:
parent
44ddb67332
commit
e151fc3d1e
7 changed files with 204 additions and 40 deletions
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
24
avisstage/templates/avisstage/formulaires/lieu.html
Normal file
24
avisstage/templates/avisstage/formulaires/lieu.html
Normal 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 %}
|
|
@ -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'),
|
||||||
|
|
|
@ -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
47
avisstage/widget.py
Normal 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
|
Loading…
Reference in a new issue