57

我想在models.pyrequest.user的方法中获取当前登录的用户() 。save我想检查用户的角色,看看它是否可以根据他的角色执行一些操作。

模型.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)

在这里,Tasks模型被用作模型中的内联Timesheet。我想检查当前登录用户的角色并根据用户的角色更新另一个模型。这里我需要request.user检查当前用户的角色。我没有使用任何表单或模板,而是完全使用 Django admin。是否有任何方法可以进入request.usersave方法或检查和更新 admin.py 中另一个模型中的值?

4

6 回答 6

41

你可以从另一个角度解决这个问题。您应该重写 AdminSites 方法,而不是更改模型保存save_model方法。在那里,您将拥有请求对象,并且可以访问已登录的用户数据,正如您已经指出的那样。

查看文档的这一章:Django ModelAdmin 文档 save_model

于 2012-06-12T09:34:15.457 回答
26

我找到了一种方法来做到这一点,但它涉及声明一个中间件。在您的应用程序中创建一个名为的文件get_username.py,其中包含以下内容:

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

编辑您的settings.py并将其添加到MIDDLEWARE_CLASSES

MIDDLEWARE_CLASSES = (
    ...
    'yourapp.get_username.RequestMiddleware',
)

现在,在您的save()方法中,您可以像这样获取当前用户名:

from get_username import get_username

...

def save(self, *args, **kwargs):
    req = get_username()
    print "Your username is: %s" % (req.user)
于 2016-03-31T08:53:03.917 回答
11

@nKn 提出的解决方案是一个很好的起点,但是当我今天尝试实施时,我遇到了两个问题:

  1. 在当前 Django 版本中,作为普通对象创建的中间件不起作用。
  2. 单元测试失败(因为它们通常在单线程中运行,所以如果第一个测试有 HTTP 请求而第二个没有,你的“请求”可能会停留在两个后续测试之间)。

这是我更新的中间件代码,它适用于 Django 1.10 并且不会破坏单元测试:

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)
于 2017-02-27T16:43:30.933 回答
8

The correct way is to use threading.local, instead of using a dictionary with threading.current_thread, since it will lead to a memory leak, since the old values will stay there for as long the application is running:

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)

    def process_exception(self, request, exception):
        request_local.request = None

    def process_template_response(self, request, response):
        request_local.request = None
        return response

If you want to access the user instead of the request, you can do get_request().user, or save the user instead of the request on __call__

于 2019-01-07T23:08:01.760 回答
7

我不认为 save_model 方法覆盖是最好的选择。例如,假设您想要保存用户信息或根据用户信息验证模型,并且 save() 不是来自视图或管理站点本身。

人们要问的是这样的结构:

def save(..)
    self.user = current_user()

或者

def save(..)
    user = current_user()
    if user.group == 'XPTO':
        error('This user cannot edit this record')

到目前为止我发现的最好的方法是:

https://bitbucket.org/q/django-current-user/overview

于 2012-11-03T01:45:21.047 回答
4

您是否尝试过使用以下库:

https://pypi.org/project/django-currentuser/

网站上如何使用它的片段:

from django_currentuser.middleware import (get_current_user, get_current_authenticated_user)
# As model field:
from django_currentuser.db.models import CurrentUserField
class Foo(models.Model):
    created_by = CurrentUserField()
于 2019-10-02T15:49:20.400 回答