Je souhaite obtenir l'utilisateur actuellement connecté (request.user
) dans la méthode save
de models.py. Je souhaite vérifier le rôle de l'utilisateur et voir s'il peut effectuer certaines opérations en fonction de son rôle.
models.py :
class TimeSheet(models.Model):
check_in_time = models.TimeField()
check_out_time = models.TimeField()
class Tasks(models.Model):
time_sheet = models.ForeignKey(TimeSheet)
project = models.ForeignKey(Project)
start_time = models.TimeField()
end_time = models.TimeField()
def save(self, *args,**kwargs):
project = SpentTime.objects.get(project__project__id = self.project.id)
start = datetime.datetime.strptime(str(self.start_time), '%H:%M:%S')
end = datetime.datetime.strptime(str(self.end_time), '%H:%M:%S')
time = float("{0:.2f}".format((end - start).seconds/3600.0))
if common.isDesigner(request.user):
SpentTime.objects.filter(project__project__id = self.project.id).update(design = float(project.design) + time)
if common.isDeveloper(request.user):
SpentTime.objects.filter(project__project__id = self.project.id).update(develop = float(project.develop) + time)
super(Tasks, self).save(*args, **kwargs)
Ici, le modèle Tasks
est utilisé comme modèle en ligne dans le modèle Timesheet
. Je souhaite vérifier le rôle de l'utilisateur actuellement connecté et mettre à jour un autre modèle en fonction du rôle de l'utilisateur. Ici, j'ai besoin de request.user
pour vérifier le rôle de l'utilisateur actuel. Je n'utilise ni formulaires ni modèles, et utilise complètement l'administrateur Django. Existe-t-il une méthode permettant d’obtenir request.user
dans la méthode save
ou de vérifier et mettre à jour les valeurs d’un autre modèle dans admin.py?
Vous pouvez aborder ce problème sous un autre angle. Au lieu de changer la méthode de sauvegarde des modèles, vous devez remplacer la méthode AdminSites save_model
. Là, vous aurez l'objet requête et pourrez accéder aux données utilisateur enregistrées comme vous l'avez déjà indiqué.
Consultez ce chapitre de la documentation: Documentation Django ModelAdmin save_model
J'ai trouvé un moyen de le faire, cela implique toutefois de déclarer un MiddleWare. Créez un fichier appelé get_username.py
dans votre application, avec le contenu suivant:
from threading import current_thread
_requests = {}
def get_username():
t = current_thread()
if t not in _requests:
return None
return _requests[t]
class RequestMiddleware(object):
def process_request(self, request):
_requests[current_thread()] = request
Éditez votre settings.py
et ajoutez-le au MIDDLEWARE_CLASSES
:
MIDDLEWARE_CLASSES = (
...
'yourapp.get_username.RequestMiddleware',
)
Maintenant, dans votre méthode save()
, vous pouvez obtenir le nom d'utilisateur actuel comme ceci:
from get_username import get_username
...
def save(self, *args, **kwargs):
req = get_username()
print "Your username is: %s" % (req.user)
Je ne pense pas que la méthode save_model soit prioritaire. Imaginez, par exemple, que vous souhaitiez enregistrer les informations utilisateur ou valider le modèle en fonction d'informations utilisateur et que save () ne provienne pas d'une vue, ni du site d'administration lui-même.
Ce que les gens demandent, ce sont des constructions comme celles-ci:
def save(..)
self.user = current_user()
ou
def save(..)
user = current_user()
if user.group == 'XPTO':
error('This user cannot edit this record')
La meilleure approche que j'ai trouvée jusqu'à présent est:
La solution proposée par @nKn est un bon point de départ, mais lorsque j'ai essayé de la mettre en œuvre aujourd'hui, j'ai rencontré deux problèmes:
Voici le code de mon middleware mis à jour, qui fonctionne avec Django 1.10 et ne casse pas:
from threading import current_thread
from Django.utils.deprecation import MiddlewareMixin
_requests = {}
def current_request():
return _requests.get(current_thread().ident, None)
class RequestMiddleware(MiddlewareMixin):
def process_request(self, request):
_requests[current_thread().ident] = request
def process_response(self, request, response):
# when response is ready, request should be flushed
_requests.pop(current_thread().ident, None)
return response
def process_exception(self, request, exception):
# if an exception has happened, request should be flushed too
_requests.pop(current_thread().ident, None)
La méthode correcte consiste à utiliser threading.local
au lieu d'utiliser un dictionnaire avec threading.current_thread
, car cela entraînerait une fuite de mémoire, car les anciennes valeurs y resteront aussi longtemps que l'application fonctionnera:
import threading
request_local = threading.local()
def get_request():
return getattr(request_local, 'request', None)
class RequestMiddleware():
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request_local.request = request
return self.get_response(request)
Si vous souhaitez accéder à l'utilisateur à la place de la demande, vous pouvez utiliser la fonction get_request().user
ou enregistrer l'utilisateur à la place de la demande sur __call__
.