Часто текущего юзера хочется иметь там, где его по умолчанию нету. Например, в формах. Для этого нужно засунуть этого юзера в тред-локалс, а потом оттуда доставать в нужном месте.
Я уже давно стырил откуда-то такой вот код для этого самого всовывания/высовывания:
# -*- coding: utf-8 -*-
try:
from threading import local
except ImportError:
from django.utils._threading_local import local
_thread_locals = local()
def set_current_user(user):
setattr(_thread_locals, 'user', user)
def get_current_user():
return getattr(_thread_locals, 'user', None)
Положим этот код, например в common.user, тогда прослойка для засовывания будет такой:
from common.user import set_current_user
class CurrentUserMiddleware(object):
def process_request(self, request):
set_current_user(getattr(request, 'user', None))
Вот и всё. Теперь в любом месте имеем текущего юзера:
from common.user import get_current_user
user = get_current_user()
...
8 коммент.:
В посте не хватает упоминания, что так делать не стоит и что нужно всегда объект текущего пользователя передавать явно.
Потому, что я так не считаю.
Да, это нарушает некоторые стереотипы проектирования. Но все эти стереотипы создавались для удобства в конечном итоге. И все они несовершенны в плане этого самого удобства. Но это несовершенство не так бросается в глаза, если позволять себе разумные отступления от правил.
В данном случае отступление мне кажется разумным. В тех проектах, где юзер часто передаётся в формы и модели, такой подход делает код короче и понятнее.
Никогда не задумывались о том, что обработка запросов от пользователей может идти в одном потоке?
Для примера посмотрите в асинхронные фреймворки twisted или tornado.
Да, всякое может быть, конечно. Однако, посте речь о Джанго. Она синхронна. И запусти её под Торнадо, например, код поста работать будет.
Действительно сейчас она синхронна. Но думаю это вопрос времени. И тогда Ваш подход не то что сломается, а станет местом жутких практически невылавливаемых граблей.
А самое главное, что Вы найдете причину подобного поведения. А вот ваши последователи нет :(
Источник (django wiki)
> это вопрос времени
Вероятность того, что mysql и sqlite станут асинхронными в обозримом будущем - ничтожна. Вероятность того, что Джанга от них откажется такая же.
А если и откажется, то прекратит работать сразу столько всего, что проблем от моих шалостей с тред-локалсами точно никто не заметит :) Может быть, я чего-то недопонимаю. В таком случае, буду признателен за науку.
> вот ваши последователи нет
Я не претендую на роль всеобщего пастыря. Если меня кто-то и беспокоит, то это люди похожие на меня. И не потому, что я плохой такой. Просто, я не могу понять непохожего на меня человека. А следовательно, не могу и помочь ему.
Так вот, люди похожие на меня, разбираются в том, что делают. Именно поэтому, код не лежит где-то в виде модуля, а составляет основу поста.
Не совсем так: для того чтобы сделать ORM асинхронный не нужно отказываться от поддержки mysql -- можно просто написать асинхронную DB библиотеку(хоть на тех же тредах).
Что касается, что плохого хранить пользователя( или любую другую инфу) в контексте треда -- тоже самое что и в глобальной переменной. Ваш код становится нереентерабельным. Результат будет зависим от внешних переменных.
Давайте закончим дисскуссию, я не против Вашего подхода, просто надо точно описывать его граничные условия и побочные эффекты.
Отправить комментарий