Промежуточное ПО django get_current_user() - странное сообщение об ошибке, которое исчезает, если исходный код "изменен", что приводит к автоматическому перезапуску сервера

Я использую промежуточное программное обеспечение, чтобы получить вошедшего в систему пользователя в моих представлениях и моделях. Это помогает мне, например, возвращать только объекты, созданные или назначенные вошедшему в систему пользователю. Пожалуйста, перейдите по этой ссылке, чтобы увидеть, какое промежуточное программное обеспечение я использую.

Я называю это промежуточное программное обеспечение с:

get_current_user()

Это работало нормально до сих пор. Но теперь я испытал какое-то странное поведение и только для одного особого варианта использования.

Я использую этот 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)

В модели проекта я установил собственный менеджер с именем user_objects. Модель проекта выглядит так (упрощенно):

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

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

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

я добавил 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

Я загрузил страницу с ошибкой: ссылка

Интересно, что когда я позволяю серверу работать (после того, как ошибка была выдана), а затем что-то изменить в моем исходном коде (добавить знак и удалить его) и сохранить его (где-то в моем проекте, не имеет значения, где!!), нажмите еще раз на ссылку, которая выкинула ошибку, все работает! Более интересным является то, что

print "current user is" + str(get_current_user())

перед строкой, которая выдает ошибку, всегда возвращает зарегистрированного пользователя правильно!

Это не имеет большого смысла для меня. Тем более, что он работает, если я просто перезагружаю (что приводит к автоматической перезагрузке сервера!) Мой источник.

Я на 100% уверен, что ошибка создается в приведенной выше исходной строке, так как я изменил это:

return super(UserProjectManager, self).get_query_set().filter(projectmembership__member=get_current_user())

к этому:

return super(UserProjectManager, self).get_query_set())

и тогда все работает отлично. Я просто говорю это, поскольку вышеприведенная ошибка, возможно, вводит в заблуждение ставку.

Наверное, трудно помочь мне здесь. Буду признателен за любую помощь!

Редактировать:

В первом ответе ниже от "whrde" говорится, что подход промежуточного программного обеспечения, вероятно, является плохой идеей, в то время как люди из другой ветки ссылок сказали, что подход хорош.

Поэтому я хотел привести другой пример, где такое промежуточное ПО действительно удобно использовать. Я использую все это в моем приложении. Мне было бы интересно, если бы мне действительно пришлось удалить это промежуточное ПО из моего приложения. так как, вероятно, я получу больше ошибок, чем тот, который я опубликовал или что подход в порядке. Например, переписать метод сохранения для модели и установить 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()

Редактирование: Заключение: не используйте промежуточное программное обеспечение get_current_user(), так как его абсолютно не нужно использовать. Передайте объект запроса вашим формам, менеджерам объектов, перезаписанным методам сохранения объектов и т. Д., И все будет хорошо;-)

2 ответа

Решение

Это выглядит как плохой подход: вам нужно передать объект запроса, чтобы предоставить функции / классу / методу доступ к текущему пользователю. Не связывайтесь с глобальным состоянием.

Создайте метод в вашем менеджере, который принимает пользователя в качестве аргумента, и вызывайте его из ваших представлений:

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

Не обращая внимания на локальное обсуждение потока, ваша проблема, вероятно, связана с тем, что AnonymousUser объект на самом деле не User экземпляр модели. Запросы к базе данных с этим объектом, возможно, не очень далеко. Вы захотите проверить аутентифицированных пользователей в какой-то момент, либо в представлении:

if request.user.is_authenticated():
    Project.objects.for_user(request.user)

Или в вашем менеджере метод:

def for_user(self, user):
    if user.is_authenticated():
        return self.get_query_set().filter(projectmembership__member=user)
    else:
        return self.get_query_set().none()
Другие вопросы по тегам