# -*- encoding: utf-8 -*- import textwrap from auf.django.emploi.models import OffreEmploi, Candidat, CandidatPiece from auf.django.references.models import Region, Bureau from django.conf import settings from django.contrib import admin from django.core.urlresolvers import reverse from django.db.models import Avg from django.forms.models import BaseInlineFormSet from django.http import HttpResponseRedirect from django.shortcuts import redirect from reversion.admin import VersionAdmin from project import groups from project.rh import models as rh from project.recrutement.forms import OffreEmploiForm from project.recrutement.models import \ Evaluateur, CandidatEvaluation, \ ProxyOffreEmploi, ProxyCandidat, MesCandidatEvaluation, \ CourrielTemplate ### CONSTANTES IMPLANTATIONS_CENTRALES = [15, 19] class BaseAdmin(admin.ModelAdmin): class Media: css = {'screen': ( 'css/admin_custom.css', 'jquery-autocomplete/jquery.autocomplete.css', )} js = ( 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', 'jquery-autocomplete/jquery.autocomplete.min.js', ) class OrderedChangeList(admin.views.main.ChangeList): """ Surcharge pour appliquer le order_by d'un annotate """ def get_query_set(self): qs = super(OrderedChangeList, self).get_query_set() qs = qs.order_by('-moyenne') return qs class OffreEmploiAdminMixin(BaseAdmin): date_hierarchy = 'date_creation' list_display = ( 'nom', 'date_limite', 'region', 'statut', 'est_affiche', '_candidatsList' ) exclude = ('actif', 'poste_nom', 'resume',) list_filter = ('statut',) actions = ['affecter_evaluateurs_offre_emploi', ] form = OffreEmploiForm ### Actions à afficher def get_actions(self, request): actions = super(OffreEmploiAdminMixin, self).get_actions(request) del actions['delete_selected'] return actions ### Affecter un évaluateurs à des offres d'emploi def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats): selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME) return HttpResponseRedirect( reverse('affecter_evaluateurs_offre_emploi') + "?ids=%s" % (",".join(selected)) ) affecter_evaluateurs_offre_emploi.short_description = \ u'Affecter évaluateur(s)' ### Afficher la liste des candidats pour l'offre d'emploi def _candidatsList(self, obj): return "Voir les candidats \ " % (reverse('admin:recrutement_proxycandidat_changelist'), obj.id) _candidatsList.allow_tags = True _candidatsList.short_description = "Afficher la liste des candidats" ### Formulaire def get_form(self, request, obj=None, **kwargs): form = super(OffreEmploiAdminMixin, self).get_form(request, obj, **kwargs) employe = groups.get_employe_from_user(request.user) user_groupes = [g.name for g in request.user.groups.all()] # Region if 'region' in form.declared_fields: region_field = form.declared_fields['region'] read_only = False elif 'region' in form.base_fields: region_field = form.base_fields['region'] read_only = False else: read_only = True if not read_only: if groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: region_field.queryset = Region.objects.all() else: region_field.queryset = Region.objects.\ filter(id=employe.implantation.region.id) # Poste if 'poste' in form.declared_fields: poste_field = form.declared_fields['poste'] read_only = False elif 'poste' in form.base_fields: poste_field = form.base_fields['poste'] read_only = False else: read_only = True if not read_only: if groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: poste_field.queryset = rh.Poste.objects.all() else: poste_field.queryset = rh.Poste.objects.\ filter(implantation__region=employe.implantation.region).\ exclude(implantation__in=IMPLANTATIONS_CENTRALES) # Bureau if 'bureau' in form.declared_fields: bureau_field = form.declared_fields['bureau'] read_only = False elif 'bureau' in form.base_fields: bureau_field = form.base_fields['bureau'] read_only = False else: read_only = True if not read_only: if groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: bureau_field.queryset = Bureau.objects.all() else: bureau_field.queryset = \ Bureau.objects.filter(region=employe.implantation.region) return form ### Queryset def queryset(self, request): qs = self.model._default_manager.get_query_set() \ .select_related('offre_emploi') user_groupes = [g.name for g in request.user.groups.all()] if groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return qs if groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.ADMINISTRATEURS in user_groupes: employe = groups.get_employe_from_user(request.user) return qs.filter(region=employe.implantation.region) if Evaluateur.objects.filter(user=request.user).exists(): evaluateur = Evaluateur.objects.get(user=request.user) offre_ids = [ e.candidat.offre_emploi_id for e in CandidatEvaluation.objects .select_related('candidat') .filter(evaluateur=evaluateur) ] return qs.filter(id__in=offre_ids) return qs.none() ### Permission add, delete, change def has_add_permission(self, request): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True return False def has_delete_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True if obj is not None: employe = groups.get_employe_from_user(request.user) if (groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes) and ( employe.implantation.region == obj.lieu_affectation.region): return True return False def has_change_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True if obj is not None: employe = groups.get_employe_from_user(request.user) if (groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes) and ( employe.implantation.region == obj.lieu_affectation.region): return True else: if groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes: return True return False class OffreEmploiAdmin(VersionAdmin, OffreEmploiAdminMixin): pass class ProxyOffreEmploiAdmin(OffreEmploiAdminMixin): list_display = ( 'nom', 'date_limite', 'region', 'statut', 'est_affiche' ) readonly_fields = ( 'description', 'bureau', 'duree_affectation', 'renumeration', 'debut_affectation', 'lieu_affectation', 'nom', 'resume', 'date_limite', 'region', 'poste' ) fieldsets = ( ('Nom', { 'fields': ('nom',) }), ('Description générale', { 'fields': ('description', 'date_limite',) }), ('Coordonnées', { 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',) }), ('Autre', { 'fields': ( 'debut_affectation', 'duree_affectation', 'renumeration', ) }), ) inlines = [] ### Lieu de redirection après le change def response_change(self, request, obj): return redirect('admin:recrutement_proxyoffreemploi_changelist') ### Formulaire def get_form(self, request, obj=None, **kwargs): form = super(ProxyOffreEmploiAdmin, self).get_form(request, obj, **kwargs) return form ### Permissions add, delete, change def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def has_change_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True if obj is not None: return True return False class CandidatPieceInline(admin.TabularInline): model = CandidatPiece fields = ('candidat', 'nom', 'path',) extra = 1 max_num = 3 class ReadOnlyCandidatPieceInline(CandidatPieceInline): readonly_fields = ('candidat', 'nom', 'path', ) cand_delete = False class CandidatEvaluationInlineFormSet(BaseInlineFormSet): """ Empêche la suppression d'une évaluation pour le CandidatEvaluationInline """ def __init__(self, *args, **kwargs): super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs) self.can_delete = False class CandidatEvaluationInline(admin.TabularInline): model = CandidatEvaluation fields = ('evaluateur', 'note', 'commentaire') max_num = 0 extra = 0 formset = CandidatEvaluationInlineFormSet ### Fields readonly def get_readonly_fields(self, request, obj=None): """ Empêche la modification des évaluations """ if obj: return self.readonly_fields + ('evaluateur', 'note', 'commentaire') return self.readonly_fields class CandidatAdminMixin(BaseAdmin): search_fields = ('nom', 'prenom') exclude = ('actif', ) list_editable = ('statut', ) list_display = ('_candidat', 'offre_emploi', 'voir_offre_emploi', 'calculer_moyenne', 'afficher_candidat', '_date_creation', 'statut', ) list_filter = ('offre_emploi', 'offre_emploi__region', 'statut', ) fieldsets = ( ("Offre d'emploi", { 'fields': ('offre_emploi', ) }), ('Informations personnelles', { 'fields': ( 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille', 'nombre_dependant' ) }), ('Coordonnées', { 'fields': ( 'telephone', 'email', 'adresse', 'ville', 'etat_province', 'code_postal', 'pays' ) }), ('Informations professionnelles', { 'fields': ( 'niveau_diplome', 'employeur_actuel', 'poste_actuel', 'domaine_professionnel' ) }), ('Traitement', { 'fields': ('statut', ) }), ) inlines = [ CandidatPieceInline, CandidatEvaluationInline, ] actions = ['envoyer_courriel_candidats'] def _candidat(self, obj): txt = u"%s %s (%s)" % (obj.nom.upper(), obj.prenom, obj.genre) txt = textwrap.wrap(txt, 30) return "
".join(txt) _candidat.short_description = "Candidat" _candidat.admin_order_field = "nom" _candidat.allow_tags = True def _date_creation(self, obj): return obj.date_creation _date_creation.admin_order_field = "date_creation" _date_creation.short_description = "Date de réception" ### Actions à afficher def get_actions(self, request): actions = super(CandidatAdminMixin, self).get_actions(request) del actions['delete_selected'] return actions ### Envoyer un courriel à des candidats def envoyer_courriel_candidats(modeladmin, obj, candidats): selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME) return HttpResponseRedirect( reverse('selectionner_template') + "?ids=%s" % (",".join(selected)) ) envoyer_courriel_candidats.short_description = u'Envoyer courriel' ### Évaluer un candidat def evaluer_candidat(self, obj): return "" \ "Évaluer le candidat" % ( reverse('admin:recrutement_candidatevaluation_changelist'), obj.id ) evaluer_candidat.allow_tags = True evaluer_candidat.short_description = 'Évaluation' ### Afficher un candidat def afficher_candidat(self, obj): items = [u"
  • %s
  • " % \ (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \ for pj in obj.pieces_jointes()] html = "Voir le candidat" % ( reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)) ) return "%s" % (html, "\n".join(items)) afficher_candidat.allow_tags = True afficher_candidat.short_description = u'Détails du candidat' ### Voir l'offre d'emploi def voir_offre_emploi(self, obj): return "Voir l'offre d'emploi" % (reverse( 'admin:recrutement_proxyoffreemploi_change', args=(obj.offre_emploi.id,) )) voir_offre_emploi.allow_tags = True voir_offre_emploi.short_description = "Afficher l'offre d'emploi" ### Calculer la moyenne des notes def calculer_moyenne(self, obj): evaluations = CandidatEvaluation.objects.filter(candidat=obj) notes = [evaluation.note for evaluation in evaluations \ if evaluation.note is not None] if len(notes) > 0: moyenne_votes = round(float(sum(notes)) / len(notes), 2) else: moyenne_votes = "Non disponible" totales = len(evaluations) faites = len(notes) if obj.statut == 'REC': if totales == faites: color = "green" elif faites > 0 and float(totales) / float(faites) >= 2: color = "orange" else: color = "red" else: color = "black" return """%s (%s/%s)""" % ( color, moyenne_votes, faites, totales ) calculer_moyenne.allow_tags = True calculer_moyenne.short_description = "Moyenne" calculer_moyenne.admin_order_field = "" ### Permissions add, delete, change def has_add_permission(self, request): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True return False def has_delete_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True return False def has_change_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True return False def get_changelist(self, request, **kwargs): return OrderedChangeList def queryset(self, request): """ Spécifie un queryset limité, autrement Django exécute un select_related() sans paramètre, ce qui a pour effet de charger tous les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les modèles de Region, il existe plusieurs boucles, ce qui conduit à la génération d'une requête infinie. """ qs = self.model._default_manager.get_query_set() \ .select_related('offre_emploi') \ .annotate(moyenne=Avg('evaluations__note')) user_groupes = [g.name for g in request.user.groups.all()] if groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return qs if groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.ADMINISTRATEURS in user_groupes: employe = groups.get_employe_from_user(request.user) return qs.filter(offre_emploi__region=employe.implantation.region) if Evaluateur.objects.filter(user=request.user).exists(): evaluateur = Evaluateur.objects.get(user=request.user) candidat_ids = [e.candidat.id for e in CandidatEvaluation.objects.filter(evaluateur=evaluateur)] return qs.filter(id__in=candidat_ids) return qs.none() class CandidatAdmin(VersionAdmin, CandidatAdminMixin): pass class ProxyCandidatAdmin(CandidatAdminMixin): list_editable = () readonly_fields = ( 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille', 'nombre_dependant', 'telephone', 'email', 'adresse', 'ville', 'etat_province', 'code_postal', 'pays', 'niveau_diplome', 'employeur_actuel', 'poste_actuel', 'domaine_professionnel', 'pieces_jointes' ) fieldsets = ( ("Offre d'emploi", { 'fields': ('offre_emploi', ) }), ('Informations personnelles', { 'fields': ( 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille', 'nombre_dependant' ) }), ('Coordonnées', { 'fields': ( 'telephone', 'email', 'adresse', 'ville', 'etat_province', 'code_postal', 'pays' ) }), ('Informations professionnelles', { 'fields': ( 'niveau_diplome', 'employeur_actuel', 'poste_actuel', 'domaine_professionnel' ) }), ) inlines = (CandidatEvaluationInline, ) def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def has_change_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True if obj is not None: evaluateur = Evaluateur.objects.get(user=request.user) for e in obj.evaluations.all(): if e.evaluateur == evaluateur: return True return False def get_actions(self, request): return None class CandidatPieceAdmin(admin.ModelAdmin): list_display = ('nom', 'candidat', ) ### Queryset def queryset(self, request): """ Spécifie un queryset limité, autrement Django exécute un select_related() sans paramètre, ce qui a pour effet de charger tous les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les modèles de Region, il existe plusieurs boucles, ce qui conduit à la génération d'une requête infinie. Affiche la liste de candidats que si le user connecté possède un Evaluateur """ qs = self.model._default_manager.get_query_set() return qs.select_related('candidat') class EvaluateurAdmin(BaseAdmin, VersionAdmin): fieldsets = ( ("Utilisateur", { 'fields': ('user',) }), ) ### Actions à afficher def get_actions(self, request): actions = super(EvaluateurAdmin, self).get_actions(request) del actions['delete_selected'] return actions ### Permissions add, delete, change def has_add_permission(self, request): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True return False def has_delete_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True return False def has_change_permission(self, request, obj=None): user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser is True or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return True return False class CandidatEvaluationAdmin(BaseAdmin): search_fields = ('candidat__nom', 'candidat__prenom') list_display = ( '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note', '_commentaire' ) readonly_fields = ('candidat', 'evaluateur') list_filter = ('candidat__statut', 'candidat__offre_emploi',) fieldsets = ( ('Évaluation du candidat', { 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', ) }), ) def get_actions(self, request): # on stocke l'evaluateur connecté (pas forcément la meilleure place...) try: self.evaluateur = Evaluateur.objects.get(user=request.user) except: self.evaluateur = None actions = super(CandidatEvaluationAdmin, self).get_actions(request) del actions['delete_selected'] return actions ### Afficher la note def _note(self, obj): """ Si l'évaluateur n'a pas encore donné de note au candidat, indiquer un lien pour Évaluer le candidat. Sinon afficher la note. """ page = self.model.__name__.lower() redirect_url = 'admin:recrutement_%s_change' % page if obj.note is None: label = "Candidat non évalué" else: label = obj.note if self.evaluateur == obj.evaluateur: return "%s" % ( reverse(redirect_url, args=(obj.id,)), label ) else: return label _note.allow_tags = True _note.short_description = "Note" _note.admin_order_field = 'note' def _statut(self, obj): return obj.candidat.get_statut_display() _statut.order_field = 'candidat__statut' _statut.short_description = 'Statut' ### Lien en lecture seule vers le candidat def _candidat(self, obj): return "%s" \ % (reverse('admin:recrutement_proxycandidat_change', args=(obj.candidat.id,)), obj.candidat) _candidat.allow_tags = True _candidat.short_description = 'Candidat' ### Afficher commentaire def _commentaire(self, obj): """ Si l'évaluateur n'a pas encore donné de note au candidat, indiquer dans le champ commentaire, Aucun au lieu de (None) Sinon afficher la note. """ if obj.commentaire is None: return "Aucun" return obj.commentaire _commentaire.allow_tags = True _commentaire.short_description = "Commentaire" ### Afficher offre d'emploi def _offre_emploi(self, obj): return "%s" % \ (reverse('admin:recrutement_proxyoffreemploi_change', args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi) _offre_emploi.allow_tags = True _offre_emploi.short_description = "Voir offre d'emploi" def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def has_change_permission(self, request, obj=None): """ Permettre la visualisation dans la changelist mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas le request.user """ user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: is_recrutement = True else: is_recrutement = False return is_recrutement def queryset(self, request): """ Afficher uniquement les évaluations de l'évaluateur, sauf si l'utilisateur est dans les groupes suivants. """ qs = self.model._default_manager.get_query_set() \ .select_related('offre_emploi') user_groupes = request.user.groups.all() user_groupes = [g.name for g in request.user.groups.all()] if request.user.is_superuser or \ groups.CORRESPONDANT_RH in user_groupes or \ groups.DRH_NIVEAU_1 in user_groupes or \ groups.DRH_NIVEAU_2 in user_groupes or \ groups.DIRECTEUR_DE_BUREAU in user_groupes or \ groups.ADMINISTRATEURS in user_groupes or \ groups.HAUTE_DIRECTION in user_groupes: return qs evaluateur = Evaluateur.objects.get(user=request.user) candidats_evaluations = \ CandidatEvaluation.objects.filter(evaluateur=evaluateur, candidat__statut__in=('REC', )) candidats_evaluations_ids = [ce.id for ce in candidats_evaluations] return qs.filter(id__in=candidats_evaluations_ids) class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin): def has_change_permission(self, request, obj=None): try: Evaluateur.objects.get(user=request.user) is_evaluateur = True except: is_evaluateur = False if obj is None and is_evaluateur: return True try: return request.user == obj.evaluateur.user except: return False def queryset(self, request): qs = self.model._default_manager.get_query_set() \ .select_related('offre_emploi') evaluateur = Evaluateur.objects.get(user=request.user) candidats_evaluations = \ CandidatEvaluation.objects.filter(evaluateur=evaluateur, candidat__statut__in=('REC', )) candidats_evaluations_ids = [ce.id for ce in candidats_evaluations] return qs.filter(id__in=candidats_evaluations_ids) class CourrielTemplateAdmin(BaseAdmin, VersionAdmin): ### Actions à afficher def get_actions(self, request): actions = super(CourrielTemplateAdmin, self).get_actions(request) del actions['delete_selected'] return actions admin.site.register(OffreEmploi, OffreEmploiAdmin) admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin) admin.site.register(Candidat, CandidatAdmin) admin.site.register(ProxyCandidat, ProxyCandidatAdmin) admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin) admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin) admin.site.register(Evaluateur, EvaluateurAdmin) admin.site.register(CourrielTemplate, CourrielTemplateAdmin)