Конечно, есть много таких подходов, как синхронный запрос, обещание, но из моего опыта я думаю, что вы должны использовать подход обратного вызова. Естественно, что асинхронное поведение Javascript. Итак, ваш фрагмент кода можно переписать немного иначе:
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
myCallback(response);
}
});
return result;
}
function myCallback(response) {
// Does something.
}
Не может быть сделано. Текущий пользователь доступен только через запрос, который недоступен при использовании чисто функциональных возможностей модели. Получите доступ к пользователю в представлении.
Вы также можете использовать django-reversion для этой цели, например.
from reversion.signals import post_revision_commit
import reversion
@receiver(post_save)
def post_revision_commit(sender, **kwargs):
if reversion.is_active():
print(reversion.get_user())
Подробнее об их API https://django-reversion.readthedocs.io/en/stable/api.html#revision-api
Игнасио прав. Модельные сигналы Django предназначены для уведомления других системных компонентов о событиях, связанных с экземплярами, и их уважаемых данных, поэтому, я думаю, это правда, что вы не можете, скажем, получить доступ к данным запроса из сигнала модели post_save
, если только эти данные запроса не были сохранены или связанный с экземпляром.
Я предполагаю, что есть много способов справиться с этим, начиная от худшего до лучшего, но я бы сказал, что это пример prime для создания класса- основанные / основанные на функции общие представления, которые автоматически будут обрабатывать это для вас.
Пусть ваши представления, которые наследуют от CreateView
, UpdateView
или DeleteView
, дополнительно наследуют от вашего класса AuditMixin
, если они обрабатывают глаголов, которые работают с моделями, которые должны быть проверены. Затем AuditMixin
может подключаться к представлениям, которые успешно создают \ обновлять \ удалять объекты и создавать запись в базе данных.
Делает совершенный смысл, очень чист, легко подключается и рождает счастливых пони. Оборотная сторона? Вы либо должны быть в выпуске выпущенной версии Django 1.3, либо вам придется потратить некоторое время, отвлекая на основе общих функций на основе функций и предоставляя новые для каждой операции аудита.
Почему бы не добавить промежуточное ПО с чем-то вроде этого:
class RequestMiddleware(object):
thread_local = threading.local()
def process_request(self, request):
RequestMiddleware.thread_local.current_user = request.user
и позже в вашем коде (особенно в сигнале в этом разделе):
thread_local = RequestMiddleware.thread_local
if hasattr(thread_local, 'current_user'):
user = thread_local.current_user
else:
user = None
Я предполагаю, что вы поняли бы это, но у меня была та же проблема, и я понял, что все экземпляры, которые я создаю, имеют ссылку на пользователя, который их создает (это то, что вы ищете)
Для отслеживания добавьте два атрибута к вашей модели (created_by
и updated_by
), в «updated_by» сохраните последнего пользователя, который изменил запись. Затем в вашем сигнале у вас есть пользователь:
models.py:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
created_by = models. (max_length=100)
updated_by = models. (max_length=100)
views.py
p = Question.objects.get(pk=1)
p.question_text = 'some new text'
p.updated_by = request.user
p.save()
signals.py
@receiver(pre_save, sender=Question)
def do_something(sender, instance, **kwargs):
try:
obj = Question.objects.get(pk=instance.pk)
except sender.DoesNotExist:
pass
else:
if not obj.user == instance.user: # Field has changed
# do something
print('change: user, old=%s new=%s' % (obj.user, instance.user))
Посмотрите django-contrib-requestprovider , возможно, вы можете его использовать.
Я смог сделать это, проверив стек и посмотрев представление, а затем посмотрел на локальные переменные для представления, чтобы получить запрос. Это похоже на хак, но это сработало.
import inspect, os
@receiver(post_save, sender=MyModel)
def get_user_in_signal(sender, **kwargs):
for entry in reversed(inspect.stack()):
if os.path.dirname(__file__) + '/views.py' == entry[1]:
try:
user = entry[0].f_locals['request'].user
except:
user = None
break
if user:
# do stuff with the user variable
context_processors.py
from django.core.cache import cache
def global_variables(request):
cache.set('user', request.user)
----------------------------------
in you model
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.core.cache import cache
from news.models import News
@receiver(pre_delete, sender=News)
def news_delete(sender, instance, **kwargs):
user = cache.get('user')
in settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
'web.context_processors.global_variables',
)