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"
|
||||
|
||||
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
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
|
@ -96,11 +96,12 @@ class Lieu(models.Model):
|
|||
# Coordonnées
|
||||
objects = geomodels.GeoManager() # Requis par GeoDjango
|
||||
coord = geomodels.PointField(u"Coordonnées",
|
||||
geography=True)
|
||||
geography=True,
|
||||
srid = 4326)
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s (%s)" % (self.name, self.ville)
|
||||
return u"%s (%s)" % (self.nom, self.ville)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Lieu"
|
||||
|
@ -161,7 +162,7 @@ class Stage(models.Model):
|
|||
return reverse('avisstage:stage', 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:
|
||||
verbose_name = "Stage"
|
||||
|
@ -173,34 +174,35 @@ class Stage(models.Model):
|
|||
class AvisStage(models.Model):
|
||||
stage = models.OneToOneField(Stage, related_name="avis_stage")
|
||||
|
||||
chapo = models.TextField(u"En quelques mots")
|
||||
avis_personnes = RichTextField(u"Les encadrants et l'équipe")
|
||||
avis_sujet = RichTextField(u"Le sujet de stage")
|
||||
avis_admin = RichTextField(u"Formalités et administration")
|
||||
chapo = models.TextField(u"En quelques mots", blank=True)
|
||||
avis_personnes = RichTextField(u"Les encadrants et l'équipe", blank=True)
|
||||
avis_sujet = RichTextField(u"Le sujet de stage", blank=True)
|
||||
avis_admin = RichTextField(u"Formalités et administration", blank=True)
|
||||
|
||||
les_plus = models.TextField(u"Les plus du stage")
|
||||
les_moins = models.TextField(u"Les moins du stage")
|
||||
les_plus = models.TextField(u"Les plus du stage", blank=True)
|
||||
les_moins = models.TextField(u"Les moins du stage", blank=True)
|
||||
|
||||
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):
|
||||
stage = models.ForeignKey(Stage)
|
||||
lieu = models.ForeignKey(Lieu)
|
||||
order = models.IntegerField("Ordre", default=0)
|
||||
|
||||
chapo = models.TextField(u"En quelques mots")
|
||||
avis_lieustage = RichTextField(u"Le lieu du stage")
|
||||
avis_pratique = RichTextField(u"S'installer - conseils pratiques")
|
||||
avis_tourisme = RichTextField(u"Dans les parages")
|
||||
chapo = models.TextField(u"En quelques mots", blank=True)
|
||||
avis_lieustage = RichTextField(u"Le lieu du stage", blank=True)
|
||||
avis_pratique = RichTextField(u"S'installer - conseils pratiques",
|
||||
blank=True)
|
||||
avis_tourisme = RichTextField(u"Dans les parages", blank=True)
|
||||
|
||||
les_plus = models.TextField(u"Les plus du lieu")
|
||||
les_moins = models.TextField(u"Les moins du lieu")
|
||||
les_plus = models.TextField(u"Les plus du lieu", blank=True)
|
||||
les_moins = models.TextField(u"Les moins du lieu", blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Avis sur un lieu de stage"
|
||||
verbose_name_plural = "Avis sur un lieu de stage"
|
||||
|
||||
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 %}
|
||||
<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>
|
||||
{% endif %}
|
||||
<p><b>Promotion :</b> {{ object.promotion }}</p>
|
||||
|
|
|
@ -2,22 +2,32 @@
|
|||
{% load staticfiles %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Profil de {{ object.nom }}</h1>
|
||||
{% if object.user == request.user %}
|
||||
<p><a href="{% url "avisstage:profil_edit" %}">Modifier mes infos</a></p>
|
||||
<h1>{{ object.sujet }}</h1>
|
||||
{% if object.auteur == user.profil %}
|
||||
<p><a href="{% url "avisstage:stage_edit" object.id %}">Modifier ce stage</a></p>
|
||||
{% endif %}
|
||||
<p><b>Promotion :</b> {{ object.promotion }}</p>
|
||||
<p>Adresse de contact : <a href="mailto:{{ object.mail }}">{{ object.mail }}</a></p>
|
||||
<article>
|
||||
<h2>Ses stages</h2>
|
||||
<ul class="stagelist">
|
||||
{% for stage in object.stages_publics %}
|
||||
<li>
|
||||
<a href="{% url "avisstage:stage" stage.id %}">
|
||||
{{ stage.sujet }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<article class="stage">
|
||||
<section class="misc">
|
||||
<h2>À propos du stage</h2>
|
||||
<p>{{ object.auteur.nom }} a fait ce stage du {{ object.date_debut }} au {{ object.date_fin }}, supervisé par {{ object.encadrants }}</p>
|
||||
<ul class="infos">
|
||||
{% for matiere in object.matieres.all %}
|
||||
<li class="matiere">{{ matiere.nom }}</li>
|
||||
{% endfor %}
|
||||
{% for thematique in object.thematiques.all %}
|
||||
<li class="thematique">{{ thematique.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{% with object.avis_stage as avis %}
|
||||
<section class="avis">
|
||||
{% if avis.chapo %}
|
||||
<p class="chapo">
|
||||
{{ avis.chapo }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endwith %}
|
||||
</article>
|
||||
{% 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'^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+)/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(),
|
||||
name='profil'),
|
||||
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.views.generic import DetailView
|
||||
|
@ -7,7 +9,8 @@ from django.urls import reverse
|
|||
from django.contrib.auth.decorators import login_required
|
||||
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
|
||||
def index(request):
|
||||
|
@ -49,15 +52,58 @@ class StageForm(forms.ModelForm):
|
|||
|
||||
class Meta:
|
||||
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):
|
||||
self.request = kwargs.pop("request")
|
||||
if "request" in kwargs:
|
||||
self.request = kwargs.pop("request")
|
||||
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):
|
||||
self.instance.auteur = self.request.user.profil
|
||||
super(StageForm, self).save(commit=commit)
|
||||
if self.instance.id is None:
|
||||
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):
|
||||
model = Stage
|
||||
|
@ -69,10 +115,43 @@ class StageAjout(CreateView, LoginRequiredMixin):
|
|||
kwargs.update({'request': self.request})
|
||||
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):
|
||||
model = Stage
|
||||
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):
|
||||
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