Кто создал, кто обновил в Django. Простой способ

21 Окт
2011

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



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

Взять пользователя лучше всего в мидльваре. Там же и создаем обработчик. Обработчиком будет каррированная функция, в которой сохранен текущий пользователь.

Код нашей мидлвары и поля. Можно выделить в отдельный модуль и сразу использовать:

from django.db import models
from django.db.models import signals
from django.utils.functional import curry
from django.utils.decorators import decorator_from_middleware
from django.contrib.auth.models import User

def update_context(user, sender, instance, **kwargs):
    registry = FieldRegistry()
    if sender in registry:
        for field in registry.get_fields(sender):
            if field.one_time and getattr(instance, field.name, None): 
                continue
            
            if isinstance(field, CurrentUserField):
                setattr(instance, field.name, user)

class CurrentContextMiddleware(object):
    def process_request(self, request):
          
        if request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            # This request shouldn't update anything,
            # so no singal handler should be attached.
            return
            
        user = request.user if hasattr(request, 'user') and request.user.is_authenticated() else None

        updater = curry(update_context, user)
        signals.pre_save.connect(updater, dispatch_uid=request, weak=False)

    def process_response(self, request, response):
        signals.pre_save.disconnect(dispatch_uid=request)
        return response
    
record_current_context = decorator_from_middleware(CurrentContextMiddleware)

class CurrentUserField(models.ForeignKey):
    def __init__(self, one_time = False, **kwargs):
        self.one_time = one_time
        super(CurrentUserField, self).__init__(User, null=True, **kwargs)

    def contribute_to_class(self, cls, name):
        super(CurrentUserField, self).contribute_to_class(cls, name)
        registry = FieldRegistry()
        registry.add_field(cls, self)


Используем так:
  • добавляем мидлвару
  • используем поле CurrentUserField

В итоге поля для сохранения создавшего и обновившего пользователя в модели будут выглядеть так:

creator = CurrentUserField(one_time = True)
updater = CurrentUserField()
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх