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

aru*_*lmr 44 python django django-models

我想request.usersavemodels.py 的方法中获取当前登录的user().我想检查用户的角色,看看它是否可以根据自己的角色执行某些操作.

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)
Run Code Online (Sandbox Code Playgroud)

这里的Tasks模型被用作Timesheet模型中的内联.我想检查当前登录用户的角色,并根据用户的角色更新另一个模型.在这里,我需要request.user检查当前用户的角色.我没有使用任何表单或模板,并完全使用Django管理员.有没有什么方法来获得request.usersave方法或在admin.py另一个模型检查和更新的价值观?

Jen*_*ens 32

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

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

  • 如果您使用内联,则使用`save_formset`https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_formset (5认同)
  • 对.实际上,如果你正在使用Django 1.4,那么"save_related"就是你的选择.不幸的是我仍然被困在Django 1.3.1的土地上,而且"save_related"还没有存在.但是,无论哪种方式,`save_formset`仍可用于完成任务. (2认同)

nKn*_*nKn 20

我找到了一种方法,但它涉及声明一个MiddleWare.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
Run Code Online (Sandbox Code Playgroud)

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

MIDDLEWARE_CLASSES = (
    ...
    'yourapp.get_username.RequestMiddleware',
)
Run Code Online (Sandbox Code Playgroud)

现在,在您的save()方法中,您可以获得如下的当前用户名:

from get_username import get_username

...

def save(self, *args, **kwargs):
    req = get_username()
    print "Your username is: %s" % (req.user)
Run Code Online (Sandbox Code Playgroud)

  • 如果线程被杀死并一次又一次地创建,则可能会在一段时间内造成内存问题。您实际上应该添加current_thread()。user = user并应以这种方式访问​​该属性。一旦线程被杀死,内存也将被释放。 (3认同)

Jos*_*sir 8

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

人们问的是那些建筑:

def save(..)
    self.user = current_user()
Run Code Online (Sandbox Code Playgroud)

要么

def save(..)
    user = current_user()
    if user.group == 'XPTO':
        error('This user cannot edit this record')
Run Code Online (Sandbox Code Playgroud)

我到目前为止找到的最佳方法是:

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

  • 确实是艾伊蒙。那是10年前的事了。现在最好的解决方案是 https://django-crum.readthedocs.io/en/latest/ (2认同)

Igo*_*kiy 8

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

  1. 在当前的Django版本中间件创建为普通对象不起作用.
  2. 单元测试失败(因为它们通常在单线程中运行,因此如果第一个测试具有HTTP请求而第二个测试没有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)
Run Code Online (Sandbox Code Playgroud)


Fra*_*uzo 8

正确的方法是使用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
Run Code Online (Sandbox Code Playgroud)

如果你想访问用户而不是请求,你可以做get_request().user,或者保存用户而不是请求__call__