Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django:在模型保存中获取当前用户_Python_Django_Django Models - Fatal编程技术网

Python Django:在模型保存中获取当前用户

Python Django:在模型保存中获取当前用户,python,django,django-models,Python,Django,Django Models,我想在models.py的save方法中获取当前登录的用户(request.user)。我想检查用户的角色,看看它是否可以根据他的角色执行一些操作 型号.py: class TimeSheet(models.Model): check_in_time = models.TimeField() check_out_time = models.TimeField() class Tasks(models.Model): time_sheet = models.Foreign

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

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

这里,
任务
模型被用作
时间表
模型中的内联。我想检查当前登录用户的角色,并根据该用户的角色更新另一个模型。这里我需要
request.user
来检查当前用户的角色。我没有使用任何形式或模板,完全利用Django管理。是否有任何方法可以在
save
方法中获取
request.user
,或者在admin.py中检查并更新另一个模型中的值?

您可以从另一个角度解决此问题。您不应更改模型保存方法,而应覆盖AdminSites
save\u model
方法。在那里,您将拥有request对象,并且可以访问您已经指出的登录用户数据


看一下文档的这一章:

我认为保存模型方法覆盖不是最好的选择。例如,假设您希望保存用户信息或基于用户信息验证模型,并且save()不是来自视图或adminsite本身

人们问的是这样的建筑:

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

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


我找到了一种方法,它包括声明一个中间件。在应用程序中创建一个名为
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
编辑您的
设置.py
并将其添加到
中间件类中:

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)

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

  • 在当前Django版本中,作为普通对象创建的中间件不起作用
  • 单元测试失败了(因为它们通常在单线程中运行,所以如果第一个测试有HTTP请求,而第二个没有,那么您的“请求”将被固定在两个后续测试之间)
  • 下面是我更新的中间件代码,它与Django 1.10一起使用,不会破坏unittests:

    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)
    

    正确的方法是使用
    threading.local
    ,而不是将字典与
    threading.current_thread
    一起使用,因为这将导致内存泄漏,因为旧值将在应用程序运行期间一直保留:

    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
    

    如果要访问用户而不是请求,可以执行
    get\u request()。user
    ,或在
    \u call\u
    上保存用户而不是请求。是否尝试使用以下库:

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

    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()
    

    谢谢你,简。我试过了。因为我在这里使用的是内联线,所以我无法用admin save_模型完成它。但是我通过添加一个created_by user foreignkey字段来完成它。如果您使用的是内联,那么您可以使用
    save_formset
    Nice one@ChrisPratt。不知道这个方法。下面几行还有一个方法
    save\u related
    。也许这也能奏效:对。事实上,如果您使用的是Django 1.4,
    save\u related
    是一个不错的选择。不幸的是,我仍然停留在Django 1.3.1的土地上,
    save\u related
    还不存在。但是,
    save\u formset
    仍然可以用于完成任务,不管是哪种方式。请注意,对于django 1.10,如果线程被终止并一次又一次地创建,这可能会在一段时间内造成内存问题。您应该实际添加current_thread().user=user,并以这种方式访问属性。一旦线程被终止,内存也会被释放。你有测试的例子吗?在我的测试中总是出现AttributeError:“非类型”对象没有属性“用户”?谢谢@不幸的是,Sascha Rau只对我的商业代码进行了测试,并对我的项目结构进行了一些内聚。如果您试图在代码中达到请求,而请求实际上并没有发出,那么您描述的行为是完全正确的。为了安全起见,请尝试一些方法,如
    request=current_request();如果请求不是None:…
    该中间件应尽快或尽可能在列表中最后一个?或者它根本不重要?@karloss它其实并不重要,因为您已经可以访问中间件中的
    请求
    对象,所以您不会在那里使用
    获取请求
    ,它也不会修改请求
    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()