django get_current_user()中间件 - 奇怪的错误信息,如果源代码被"更改",它就会消失,从而导致服务器自动重启

Tho*_*mel 7 django

我正在使用中间件来获取我的视图和模型中当前登录的用户.这有助于我例如仅返回创建或分配给登录用户的对象.请点击此链接查看我使用的中间件.

我将此中间件称为:

get_current_user()
Run Code Online (Sandbox Code Playgroud)

到目前为止这个工作正常.但现在我经历了一些奇怪的行为,只针对一个特殊的用例.

我在自定义管理器中使用此get_current_user()仅返回当前登录用户所属的项目.成员资格通过"ProjectMembership"模型定义.这个模型看起来像这样:

class ProjectMembership(models.Model):
    project = models.ForeignKey(Project)
    member = models.ForeignKey(User, related_name='project_membership_member_set')
    day_rate = models.PositiveIntegerField(max_length=11)
Run Code Online (Sandbox Code Playgroud)

在项目模型中,我设置了一个名为user_objects的自定义管理器.项目模型看起来像这样(简化):

class Project(models.Model):
    name = models.CharField(max_length=100)

    #Managers
    objects = models.Manager()
    user_objects=UserProjectManager()
Run Code Online (Sandbox Code Playgroud)

UserProjectManager()现在是我的关注点.经理看起来像这样:

class UserProjectManager(models.Manager):
    def get_query_set(self):
        print "current user is" + str(get_current_user())
        return super(UserProjectManager, self).get_query_set().filter(projectmembership__member=get_current_user())
Run Code Online (Sandbox Code Playgroud)

我添加print "current user is" + str(get_current_user())了以便调试它.这个打印声明总是!打印出当前登录的用户.当我创建此函数时,服务器(manage.py runserver)正在运行,我没有重新启动服务器,并且该方法按照我的预期运行.

但是,如果我使用manage.py runserver重新启动服务器,则UserProjectManager()会因此错误而崩溃:

caught an exception while rendering: Incorrect integer value: 'AnonymousUser' for column 'member_id' at row 1
Run Code Online (Sandbox Code Playgroud)

我上传了错误页面:链接

有趣的是,当我让服务器运行时(在抛出错误之后)然后在我的源代码中更改某些内容(添加一个符号并删除它)并保存它(在我的项目中的某个地方,无所谓! ),再次点击抛出错误的链接,它的工作原理!更有趣的是

print "current user is" + str(get_current_user())
Run Code Online (Sandbox Code Playgroud)

在抛出错误的行前面,始终正确返回登录用户!

这对我来说没有多大意义.特别是因为它可以工作,如果我只是重新保存(这导致自动重启服务器!)我的来源.

我100%确定在上面列出的源代码行中创建了错误,因为我改变了这个:

return super(UserProjectManager, self).get_query_set().filter(projectmembership__member=get_current_user())
Run Code Online (Sandbox Code Playgroud)

对此:

return super(UserProjectManager, self).get_query_set())
Run Code Online (Sandbox Code Playgroud)

然后它工作得很好.我只是这样说,因为上面发布的错误可能是一个误导性的出价.

可能很难帮我在这里.非常感谢任何帮助!

编辑:

下面第一个回答"whrde"表示中间件方法可能是一个坏主意,而另一个线程链接的人说这种方法很好.

因此,我想说明这样一个中间件非常方便使用的另一个例子.我在我的应用程序中使用它.如果我真的应该从我的应用程序中删除此中间件,我会感兴趣.因为我可能会得到比我发布的错误更多的错误或者方法很好.例如,覆盖模型的save方法并设置current_user在使用此中间件时非常容易.它节省了我在save()的每个视图中写相同的三行.

class ProjectMembership(models.Model):
    project = models.ForeignKey(Project)
    member = models.ForeignKey(User, related_name='project_membership_member_set')
    day_rate = models.PositiveIntegerField(max_length=11)

    created_by = models.ForeignKey(User, editable=False, related_name='project_membership_creator')
    created = models.DateTimeField(auto_now_add=True, editable=False, verbose_name='creation date')
    modified_by = models.ForeignKey(User, editable=False, related_name='project_membership_modifier')
    modified = models.DateTimeField(auto_now=True, editable=False)

    #Managers
    objects = models.Manager()
    user_objects=UserProjectMembershipManager()

    class Meta:
        unique_together = (("project", "member"),)

    def __unicode__(self):
        return u'%s in project: %s' % (self.member, self.project)

    def save(self):
        if not self.id:
            self.created_by = get_current_user()
        self.modified_by = get_current_user()
        super(ProjectMembership, self).save()
Run Code Online (Sandbox Code Playgroud)

编辑:Conclusio:不要使用get_current_user()中间件,因为绝对不需要使用它.将请求对象传递给表单,对象管理器,覆盖对象保存方法等等.一切都会好的;-)

Wil*_*rdy 9

这看起来是一个糟糕的方法:您需要传递请求对象以提供可访问当前用户的函数/类/方法.不要乱用全球状态.

在您的经理上创建一个方法,将用户作为参数,并从您的视图中调用它:

# models.py
class ProjectMembership(models.Model):
    project = models.ForeignKey(Project)
    member = models.ForeignKey(User, related_name='project_membership_member_set')
    day_rate = models.PositiveIntegerField(max_length=11)

class ProjectManager(models.Manager):
    def for_user(self, user):
        return self.get_query_set().filter(projectmembership__member=user)

class Project(models.Model):
    name    = models.CharField(max_length=100)
    objects = ProjectManager()

# somewhere deep in views.py
if request.user.is_authenticated():
    Project.objects.for_user(request.user)
Run Code Online (Sandbox Code Playgroud)

  • 我总是做这样的事情.与使用中间件和线程本地存储相比,这是一种更简单,更明确的方法. (4认同)