СУХОЙ способ добавить созданный / измененный и время - PullRequest
59 голосов
/ 21 января 2011

Имея что-то вроде

  • создал_бай
  • создан_дата
  • updated_by
  • updated_date

было бы оченьобщий шаблон для многих таблиц.

1) Вы можете установить дату создания автоматически (но не другие) в model.py с помощью

created_date = models.DateTimeField(auto_now_add=True, editable=False)

2) Вы можете создавать / изменять даты(но не пользователем /, так как не имеет контекста запроса) в model.py с

def save(self):
    if self.id:
        self.modified_date = datetime.now()
    else:
        self.created_date = datetime.now()
    super(MyModel,self).save()

3) Вы можете установить дату создания / изменения и в admin.py - но это не такиметь дело с обновлениями без прав администратора

def save_model(self, request, obj, form, change):
    if change:
        obj.modified_by = request.user
        obj.modified_date = datetime.now()
    else:
        obj.created_by = request.user
        obj.created_date = datetime.now()
    obj.save()

4) И последнее место будет в view.py, который может выполнять все 4, но не распространяется на обновления администратора.

Так что реально естьчтобы логика распространялась, как минимум, повторяясь в 3 и 4 (или метод в модели, вызываемый из обоих, который будет пропущен)

Что лучше?(Я работал с python / django в течение нескольких дней, поэтому я мог легко упустить что-то очевидное)

  • Можете ли вы сделать что-то вроде @login_required, например @ audit_changes
  • Можете ли выполучить доступ к запросу и текущему пользователю в модели и централизовать логику там?

Ответы [ 3 ]

91 голосов
/ 14 июня 2012

Django теперь может обрабатывать даты создания / изменения, поэтому они могут быть реализованы следующим образом:

class BaseModel(models.Model):
    created_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

Добавив это в базовый класс абстрактной модели, его можно легко добавить ко всем моделям приложения.

Хранить пользователя сложнее, поскольку request.user недоступен. Как упомянул SeanOC, это разделение проблем между веб-запросом и уровнем модели. Либо вы все время пропускаете это поле, либо сохраняете request.user в локальном потоке. Django CMS делает это для своей системы разрешений.

class CurrentUserMiddleware(object):
    def process_request(self, request):
        set_current_user(getattr(request, 'user', None))

И отслеживание пользователя происходит в другом месте:

from threading import local
_thread_locals = local()

def set_current_user(user):
    _thread_locals.user=user

def get_current_user():
    return getattr(_thread_locals, 'user', None)

Для не-веб-сред (например, команд управления) вам нужно будет вызвать set_current_user в начале скрипта.

9 голосов
/ 21 января 2011

Для моделей с метками времени вы, вероятно, захотите взглянуть на django-model-utils или django-extensions . Каждый из них включает абстрактные базовые классы, которые автоматически обрабатывают созданную и последнюю измененную временную метку. Вы можете использовать эти инструменты напрямую или посмотреть, как они решили проблему, и найти собственное решение.

Что касается других ваших вопросов:

Можете ли вы сделать что-то вроде @login_required, например @ Audit_changes

Потенциально, да, но вы должны быть очень осторожны, чтобы обеспечить безопасность потоков. Что вы могли бы сделать - это в своем декораторе @audit_changes установить флаг, чтобы включить аудит в локальном потоке. Затем либо в методе сохранения ваших моделей, либо в обработчике сигналов вы можете проверить свой флаг аудита и записать данные аудита, если этот флаг был установлен.

Можете ли вы получить доступ к запросу и текущему пользователю в модели и централизовать логику там?

Да, но вы сделаете компромисс. Как вы уже коснулись, существует очень четкое и преднамеренное разделение проблем между ORM Django и его битами обработки запросов / аутентификации. Есть два способа получить информацию из запроса (текущего пользователя) в ORM (ваши модели). Вы можете вручную управлять обновлением информации о создателе / ​​модификаторе своих объектов или настроить механизм для автоматической обработки этих работ по обслуживанию. Если вы выберете ручной подход (передача информации через вызовы методов из запроса в представлении в ORM), это будет больше кода для поддержки / тестирования, но вы сохраните разделение проблем на месте. При ручном подходе вы будете в гораздо лучшей форме, если вам когда-нибудь придется работать с вашими объектами вне цикла запрос / ответ (например, cron-скрипты, отложенные задачи, интерактивная оболочка). Если вы согласны с тем, чтобы устранить это разделение интересов, то вы можете настроить что-то, где вы установите локальный поток с текущим пользователем в промежуточном программном обеспечении, а затем посмотреть на этот локальный поток в методе сохранения вашей модели. В противоположность ручному подходу, у вас будет меньше кода для работы, но вам будет гораздо труднее, если вы когда-нибудь захотите работать с вашими объектами вне цикла запрос / ответ. Кроме того, вам нужно быть очень осторожным, чтобы сохранить все потоки с более автоматизированным подходом.

0 голосов
/ 21 января 2011

Можете ли вы импортировать объект модели User и вызвать get_current ()?

Кроме того, я думаю, что вы можете вызывать представления в admin.py.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...